home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / dev / lang / SmallEiffel.lha / SmallEiffel / lib_se / eiffel_parser.e < prev    next >
Text File  |  1998-12-22  |  114KB  |  4,731 lines

  1. --          This file is part of SmallEiffel The GNU Eiffel Compiler.
  2. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  3. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  4. --                       http://www.loria.fr/SmallEiffel
  5. -- SmallEiffel is  free  software;  you can  redistribute it and/or modify it 
  6. -- under the terms of the GNU General Public License as published by the Free
  7. -- Software  Foundation;  either  version  2, or (at your option)  any  later 
  8. -- version. SmallEiffel is distributed in the hope that it will be useful,but
  9. -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. -- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License 
  11. -- for  more  details.  You  should  have  received a copy of the GNU General 
  12. -- Public  License  along  with  SmallEiffel;  see the file COPYING.  If not,
  13. -- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14. -- Boston, MA 02111-1307, USA.
  15. --
  16. class EIFFEL_PARSER
  17.    --
  18.    -- Singleton object in charge of Eiffel parsing.
  19.    -- This singleton is shared via the GLOBALS.`eiffel_parser' once function.
  20.    --
  21.  
  22. inherit GLOBALS;
  23.    
  24. creation make
  25.    
  26. feature {NONE}
  27.    
  28.    make is 
  29.       do 
  30.       end;
  31.  
  32. feature {UNIQUE_STRING}
  33.    
  34.    case_insensitive: BOOLEAN;
  35.      -- When flag "-case_insensitive" is on.
  36.  
  37. feature {NONE}
  38.  
  39.    drop_comments: BOOLEAN;
  40.      -- When objects COMMENT are not necessary.
  41.  
  42. feature 
  43.    
  44.    is_running: BOOLEAN;
  45.      -- True when the parser is running (ie. parsing of the 
  46.      -- current class is not finished)..
  47.  
  48. feature {SMALL_EIFFEL} 
  49.       
  50.    analyse_class(class_name: CLASS_NAME): BASE_CLASS is
  51.       require
  52.      parser_buffer.is_ready;
  53.      not is_running;
  54.      not small_eiffel.is_ready
  55.       local
  56.      old_nbe, old_nbw: INTEGER;
  57.      path: STRING; 
  58.       do
  59.      path := parser_buffer.path;
  60.      if nb_errors > 0 then
  61.         eh.append("Correct previous error(s) first.");
  62.         eh.print_as_fatal_error;
  63.      end;
  64.      debug
  65.         if small_eiffel.is_ready then
  66.            eh.append("Tried to load class ");
  67.            eh.append(path);
  68.            eh.append(" while small_eiffel `is_ready'.");
  69.            eh.print_as_warning;
  70.         end;
  71.      end;
  72.      echo.put_integer(small_eiffel.base_class_count + 1);
  73.      echo.put_character('%T');
  74.      echo.put_string(path);
  75.      echo.put_character('%N');
  76.      old_nbe := nb_errors;
  77.      old_nbw := nb_warnings;
  78.      is_running := true;
  79.      inside_function := false; 
  80.      inside_once_function := false; 
  81.      in_ensure := false;
  82.      last_comments := Void;
  83.      line := 1;
  84.      column := 1;
  85.      current_line := parser_buffer.item(line);
  86.      if current_line.count = 0 then
  87.         cc := '%N';
  88.         else
  89.         cc := current_line.first;
  90.      end;
  91.      !!last_base_class.make;
  92.      skip_comments;
  93.      a_class_declaration; 
  94.      is_running := false;
  95.      parser_buffer.unset_is_ready;
  96.      Result := last_base_class;
  97.      if nb_errors - old_nbe > 0 then
  98.         show_nb_errors;
  99.         echo.w_put_string("Load class %"");
  100.         echo.w_put_string(path);
  101.         echo.w_put_string("%" aborted.%N");
  102.         Result := Void;
  103.      elseif nb_warnings - old_nbw > 0 then
  104.         show_nb_warnings;
  105.         check
  106.            Result /= Void
  107.         end;
  108.      end;
  109.      if Result /= Void then
  110.         small_eiffel.add_class(Result);
  111.         if class_name /= Void and then 
  112.            class_name.to_string /= Result.name.to_string 
  113.          then
  114.            eh.add_position(class_name.start_position);
  115.            eh.append(fz_01);
  116.            eh.append(path);
  117.            eh.append("%" does not contains class %"");
  118.            eh.append(class_name.to_string);
  119.            fatal_error(fz_03);
  120.         end;
  121.         Result.get_started;
  122.      end;
  123.       ensure
  124.      not parser_buffer.is_ready
  125.       end;
  126.  
  127. feature {COMPILE_TO_C, SHORT}
  128.    
  129.    set_case_insensitive is
  130.       do
  131.      case_insensitive := true;
  132.       end;
  133.  
  134. feature {POSITION}
  135.  
  136.    current_class_name: CLASS_NAME is
  137.      -- The name of the class the parser is parsing.
  138.       require
  139.      is_running
  140.       do
  141.      Result := last_base_class.name;
  142.       ensure
  143.      Result /= Void
  144.       end;
  145.  
  146.    current_class: BASE_CLASS is
  147.      -- The class the parser is parsing.
  148.       require
  149.      is_running
  150.       do
  151.      Result := last_base_class;
  152.       ensure
  153.      Result /= Void
  154.       end;
  155.  
  156. feature {CECIL_POOL}
  157.  
  158.    connect_to_cecil: STRING is
  159.       -- Return the cecil file path (first line).
  160.       require
  161.      not is_running;
  162.      nb_errors = 0;
  163.      run_control.cecil_path /= Void
  164.       local
  165.      path: STRING;
  166.       do
  167.      path := run_control.cecil_path;
  168.      echo.put_string("Parsing Cecil File : ");
  169.      echo.put_string(path);
  170.      echo.put_character('%N');
  171.      parser_buffer.load_file(path);
  172.      if not parser_buffer.is_ready then
  173.         fatal_error(
  174.             "Cannot open Cecil file (use -verbose flag for details).");
  175.      end;
  176.      is_running := true;
  177.      formal_generic_list := Void;
  178.      inside_function := false; 
  179.      inside_once_function := false; 
  180.      in_ensure := false;
  181.      last_comments := Void;
  182.      line := 1;
  183.      column := 1;
  184.      current_line := parser_buffer.item(line);
  185.      !!last_base_class.make;
  186.      current_class_name.identify("Cecil file");
  187.      small_eiffel.add_class(last_base_class);
  188.      if current_line.count = 0 then
  189.         cc := '%N';
  190.         else
  191.         cc := current_line.first;
  192.      end;
  193.      skip_comments;
  194.      from
  195.         !!Result.make(32);
  196.      until
  197.         cc = '%N'
  198.      loop
  199.         Result.extend(cc);
  200.         next_char;
  201.      end;
  202.      skip_comments;
  203.       end;
  204.  
  205.    end_of_input: BOOLEAN is
  206.       do
  207.      Result := cc = end_of_text;
  208.       end;
  209.  
  210.    parse_c_name: STRING is
  211.       do
  212.      from
  213.         !!Result.make(32);
  214.      until
  215.         cc.is_separator
  216.      loop
  217.         Result.extend(cc);
  218.         next_char;
  219.      end;
  220.      skip_comments;
  221.       end;
  222.  
  223.    parse_run_type: TYPE is
  224.       do
  225.      if a_class_type then
  226.         Result := last_class_type;
  227.      else
  228.         fcp(em18);
  229.      end;
  230.       ensure
  231.      nb_errors = 0
  232.       end;
  233.       
  234.    parse_feature_name: FEATURE_NAME is
  235.       do
  236.      if a_feature_name then
  237.         Result := last_feature_name;
  238.      else
  239.         fcp(em2);
  240.      end;
  241.       ensure
  242.      nb_errors = 0
  243.       end;
  244.  
  245.    disconnect is
  246.       do
  247.      is_running := false;
  248.      parser_buffer.unset_is_ready;
  249.       end;
  250.       
  251. feature {NONE}
  252.    
  253.    line, column: INTEGER; 
  254.      -- Current `line' number and current `column' number.
  255.    
  256.    current_line: STRING; 
  257.      -- Current line string of `text'.
  258.    
  259.    cc: CHARACTER; 
  260.      -- Current character in the `current_line'.
  261.    
  262.    current_position: POSITION is
  263.       do
  264.      !!Result.make(line,column);
  265.       end;
  266.  
  267.    tmp_feature: TMP_FEATURE is
  268.       once
  269.      !!Result;
  270.       end;
  271.  
  272. feature {C_PRETTY_PRINTER}
  273.  
  274.    show_nb_warnings is
  275.       do
  276.      show_nb(nb_warnings," warning(s).%N");
  277.       end;
  278.  
  279.    show_nb_errors is
  280.       do
  281.      show_nb(nb_errors," error(s).%N");
  282.       end;
  283.  
  284. feature {NONE}
  285.    
  286.    show_nb(nb: INTEGER; tail: STRING) is
  287.       do
  288.      if nb > 0 then
  289.         echo.w_put_string(fz_error_stars);
  290.         echo.w_put_integer(nb);
  291.         echo.w_put_string(tail);
  292.      end;
  293.       end;
  294.  
  295. feature {NONE}
  296.    
  297.    fcp(msg: STRING) is
  298.       do
  299.      eh.add_position(current_position);
  300.      fatal_error(msg);
  301.       end;
  302.    
  303. feature {TMP_FEATURE}
  304.  
  305.    ecp(msg: STRING) is
  306.       do
  307.      error(current_position,msg);
  308.       end;
  309.    
  310. feature {NONE}
  311.  
  312.    wcp(msg: STRING) is
  313.       do
  314.      warning(current_position,msg);
  315.       end;
  316.    
  317.    err_exp(sp: POSITION; operator: STRING) is
  318.      -- When an error occurs in the right hand side of `operator'.
  319.       local
  320.      msg: STRING;
  321.       do
  322.      !!msg.make(0);
  323.      msg.append("Right hand side expression of %"");
  324.      msg.append(operator);
  325.      msg.append("%" expected.");
  326.      eh.add_position(sp);
  327.      fatal_error(msg);
  328.       end;
  329.    
  330.    end_of_text: CHARACTER is '%/0/'; -- Flag of the end of the `text'. 
  331.    
  332.    last_comments: COMMENT; 
  333.      -- Void or waiting comment.
  334.    
  335.    inside_function: BOOLEAN; 
  336.      -- True when a function (once or non-once) is parsed.
  337.  
  338.    inside_once_function: BOOLEAN; 
  339.      -- True when a once function is parsed.
  340.  
  341. feature {NONE}
  342.    
  343.    formal_generic_list: FORMAL_GENERIC_LIST;
  344.      -- Void or not empty list of formal generic arguments.
  345.    
  346.    in_ensure: BOOLEAN; 
  347.      -- True during the parsing of a ensure clause.
  348.    
  349.    in_rescue: BOOLEAN; 
  350.      -- True during the parsing of a rescue clause.
  351.    
  352.    arguments: FORMAL_ARG_LIST; 
  353.      -- Void or actual formal arguments list.
  354.  
  355.    local_vars: LOCAL_VAR_LIST; 
  356.      -- Void or actual local variables list. 
  357.            
  358.    ok: BOOLEAN; 
  359.      -- Dummy variable to call functions.
  360.    
  361. feature {NONE} -----------------------------------------------------------------
  362.    -- List of once tmp_* objects. 
  363.    
  364.    tmp_name: TMP_NAME is
  365.       once
  366.      !!Result.make;
  367.       end;
  368.    
  369. feature {NONE} -----------------------------------------------------------------
  370.    -- This list of variables is used to store the last encountered element
  371.    -- during syntax analysis.
  372.    
  373.    last_ascii_code: INTEGER;
  374.    last_base_class: BASE_CLASS;
  375.    last_base_type: TYPE;
  376.    last_binary: INFIX_NAME;
  377.    last_bit_constant: BIT_CONSTANT;
  378.    last_boolean_constant: BOOLEAN_CONSTANT;
  379.    last_character_or_integer: BASE_TYPE_CONSTANT;
  380.    last_character_constant: CHARACTER_CONSTANT;
  381.    last_class_name: CLASS_NAME;
  382.    last_class_type: TYPE;
  383.    last_expression: EXPRESSION;
  384.    last_feature_declaration: E_FEATURE;
  385.    last_feature_name: FEATURE_NAME;
  386.    last_feature_name_list: FEATURE_NAME_LIST;
  387.    last_keyword: STRING;
  388.    last_type_formal_generic: TYPE_FORMAL_GENERIC;
  389.    last_infix: INFIX_NAME; 
  390.    last_prefix: PREFIX_NAME;
  391.    last_integer_constant: INTEGER_CONSTANT;
  392.    last_instruction: INSTRUCTION;
  393.    last_index_value: EXPRESSION;
  394.    last_manifest_constant: EXPRESSION;
  395.    last_manifest_string: MANIFEST_STRING;
  396.    last_parent: PARENT;
  397.    last_real_constant: REAL_CONSTANT;
  398.    last_type: TYPE;
  399.    last_tag_mark: TAG_NAME;
  400.    
  401. feature {NONE} ----------------------------------------------------------------
  402.    -- Following functions never move cc.
  403.    
  404.    a_argument: BOOLEAN is
  405.       local
  406.      rank: INTEGER;
  407.       do        
  408.      if arguments /= Void then
  409.         rank := arguments.rank_of(tmp_name.to_string);
  410.         if rank > 0 then
  411.            last_expression := tmp_name.to_argument_name2(arguments,rank);
  412.            Result := true;
  413.         end;
  414.      end;
  415.       end;
  416.    
  417.    a_current: BOOLEAN is
  418.       do
  419.      if tmp_name.is_current then
  420.         !WRITTEN_CURRENT!last_expression.make(tmp_name.start_position);
  421.         Result := true;
  422.      end;
  423.       end;
  424.    
  425.    a_formal_arg_list is
  426.      -- formal_arg_list -> ["(" {declaration_group ";" ...} ")"]
  427.      --++ declaration_group -> {identifier "," ...}+ ":" type
  428.       local
  429.      started: BOOLEAN;
  430.      name: ARGUMENT_NAME1;
  431.      name_list: ARRAY[ARGUMENT_NAME1];
  432.      declaration: DECLARATION;
  433.      list: ARRAY[DECLARATION];
  434.      state: INTEGER;
  435.      -- state 0 : waiting for "(".
  436.      -- state 1 : waiting for the first name of a group.
  437.      -- state 2 : waiting "," or ":".
  438.      -- state 3 : waiting for a name (not the first).
  439.      -- state 4 : waiting for type mark.
  440.      -- state 5 : waiting ";" or ")".
  441.      -- state 6 : end. 
  442.      -- state 7 : error.
  443.       do
  444.      from  
  445.         arguments := Void;
  446.      until
  447.         state > 5
  448.      loop
  449.         inspect 
  450.            state
  451.         when 0 then
  452.            if skip1('(') then
  453.           started := true;
  454.           state := 1;
  455.            else
  456.           state := 6;
  457.            end;
  458.         when 1 then
  459.            if a_identifier then
  460.           name := tmp_name.to_argument_name1;
  461.           state := 2;
  462.            elseif skip1(')') then
  463.           state := 6;
  464.            else
  465.           state := 7;
  466.            end;
  467.         when 2 then
  468.            if skip1(':') then
  469.           if name_list /= Void then
  470.              name_list.add_last(name);
  471.              name := Void;
  472.           end;
  473.           state := 4;
  474.            else
  475.           ok := skip1(',');
  476.           if name_list = Void then
  477.              name_list := <<name>>;
  478.           else
  479.              name_list.add_last(name);
  480.           end;
  481.           name := Void;
  482.           state := 3;
  483.            end;
  484.         when 3 then
  485.            if a_identifier then
  486.           name := tmp_name.to_argument_name1;
  487.           state := 2;
  488.            elseif cc = ',' or else cc = ';' then
  489.           wcp(em13);
  490.           ok := skip1(',') or else skip1(';');
  491.            else
  492.           state := 7;
  493.            end;
  494.         when 4 then
  495.            if a_type then
  496.           if name_list /= Void then
  497.              !DECLARATION_GROUP!declaration.make(name_list,last_type);
  498.              name_list := Void;
  499.           else
  500.              !DECLARATION_1!declaration.make(name,last_type);
  501.              name := Void;
  502.           end;
  503.           if list = Void then
  504.              list := <<declaration>>;
  505.           else
  506.              list.add_last(declaration)
  507.           end;
  508.           declaration := Void;
  509.           state := 5;
  510.            else
  511.           state := 7;
  512.            end;
  513.         else -- state = 5
  514.            if skip1(')') then
  515.           state := 6;
  516.            elseif cc = ',' then
  517.           wcp("Substitute with %";%".");
  518.           ok := skip1(',');
  519.           state := 1;
  520.            else
  521.           ok := skip1(';'); 
  522.           state := 1;
  523.            end;
  524.         end;
  525.      end;
  526.      if state = 7 then
  527.         fcp("Bad formal aguments list.");
  528.      elseif started then
  529.         if list = Void then
  530.            wcp("Empty formal argument list (deleted).");
  531.         else
  532.            !!arguments.make(list);
  533.            tmp_feature.set_arguments(arguments);
  534.         end;
  535.      end;
  536.       end;
  537.    
  538.    a_local_var_list is
  539.      -- local_var_list -> [{declaration_group ";" ...}]
  540.      --++ declaration_group -> {identifier "," ...}+ ":" type
  541.       local
  542.      name: LOCAL_NAME1;
  543.      name_list: ARRAY[LOCAL_NAME1];
  544.      declaration: DECLARATION;
  545.      list: ARRAY[DECLARATION];
  546.      rank, state: INTEGER;
  547.      -- state 0 : waiting for the first name of a group.
  548.      -- state 1 : waiting "," or ":".
  549.      -- state 2 : waiting for a name (not the first).
  550.      -- state 3 : waiting for type mark.
  551.      -- state 4 : waiting ";".
  552.      -- state 5 : end. 
  553.      -- state 6 : error.
  554.       do
  555.      from  
  556.      until
  557.         state > 4
  558.      loop
  559.         inspect 
  560.            state
  561.         when 0 then
  562.            if a_identifier then
  563.           name := tmp_name.to_local_name1;
  564.           state := 1;
  565.           if arguments /= Void then
  566.              rank := arguments.rank_of(name.to_string); 
  567.              if rank > 0 then
  568.             eh.add_position(name.start_position);
  569.             eh.add_position(arguments.name(rank).start_position);
  570.             eh.error("Same identifier appears twice (local/formal).");
  571.              end;
  572.           end;
  573.            elseif cc = ',' or else cc = ';' then
  574.           wcp(em13);
  575.           ok := skip1(',') or else skip1(';');
  576.            else
  577.           state := 5;
  578.            end;
  579.         when 1 then
  580.            if skip1(':') then
  581.           if name_list /= Void then
  582.              name_list.add_last(name);
  583.              name := Void;
  584.           end;
  585.           state := 3;
  586.            else
  587.           if cc = ';' then
  588.              wcp("Substitute with %",%".");
  589.              ok := skip1(';');
  590.           else
  591.              ok := skip1(',');
  592.           end;
  593.           if name_list = Void then
  594.              name_list := <<name>>;
  595.           else
  596.              name_list.add_last(name);
  597.           end;
  598.           name := Void;
  599.           state := 2;
  600.            end;
  601.         when 2 then
  602.            if a_identifier then
  603.           name := tmp_name.to_local_name1;
  604.           state := 1;
  605.           if arguments /= Void then
  606.              rank := arguments.rank_of(name.to_string); 
  607.              if rank > 0 then
  608.             eh.add_position(name.start_position);
  609.             eh.add_position(arguments.name(rank).start_position);
  610.             eh.error("Same identifier appears twice (local/formal).");
  611.              end;
  612.           end;
  613.            elseif cc = ',' or else cc = ';' then
  614.           wcp(em13);
  615.           ok := skip1(',') or else skip1(';');
  616.            else
  617.           state := 6;
  618.            end;
  619.         when 3 then
  620.            if a_type then
  621.           if name_list /= Void then
  622.              !DECLARATION_GROUP!declaration.make(name_list,last_type);
  623.              name_list := Void;
  624.           else
  625.              !DECLARATION_1!declaration.make(name,last_type);
  626.              name := Void;
  627.           end;
  628.           if list = Void then
  629.              list := <<declaration>>;
  630.           else
  631.              list.add_last(declaration);
  632.           end;
  633.           state := 4;
  634.            else
  635.           state := 6;
  636.            end;
  637.         else -- state = 4
  638.            if cc = ',' then
  639.           wcp("Substitute with %";%".");
  640.           ok := skip1(',');
  641.           state := 0;
  642.            else
  643.           ok := skip1(';');
  644.           state := 0;
  645.            end;
  646.         end;
  647.      end;
  648.      if state = 6 then
  649.         fcp("Bad local variable list.");
  650.      elseif list /= Void then
  651.         !!local_vars.make(list);
  652.         tmp_feature.set_local_vars(local_vars);
  653.      end;
  654.       end;
  655.    
  656.    a_local_variable: BOOLEAN is
  657.       local
  658.      rank: INTEGER;
  659.       do
  660.      if local_vars /= Void then
  661.         rank := local_vars.rank_of(tmp_name.to_string);
  662.         if rank > 0 then
  663.            last_expression := tmp_name.to_local_name2(local_vars,rank);
  664.            Result := true;
  665.         end;
  666.      end;
  667.       end;
  668.    
  669.    a_result: BOOLEAN is
  670.       do
  671.      if tmp_name.is_result then
  672.         last_expression := last_result;
  673.         Result := true;
  674.      end;
  675.       end;
  676.    
  677.    a_void: BOOLEAN is
  678.       do
  679.      if tmp_name.is_void then
  680.         last_expression := tmp_name.to_e_void;
  681.         Result := true;
  682.      end;
  683.       end;
  684.    
  685.    get_comments: COMMENT is
  686.       do
  687.      Result := last_comments;
  688.      last_comments := Void;
  689.       end;
  690.  
  691. feature {NONE} ----------------------------------------------------------------
  692.    -- Very low level character and text manipulation.
  693.    
  694.    start_line, start_column: INTEGER;
  695.      -- To store beginning position of : `a_keyword', `a_integer', 
  696.      -- `a_real', `skip1', `skip2' and `skip1unless2'.
  697.    
  698.    a_keyword(keyword: STRING): BOOLEAN is
  699.      -- Look for `keyword' beginning strictly at current position.
  700.      -- A keyword is never followed by a character of
  701.      -- this set : 'A'..'Z','a'..'z','0'..'9','_'.
  702.      -- When Result is true, `last_keyword' is updated. 
  703.       require
  704.      not keyword.empty
  705.       local
  706.      i, keyword_count: INTEGER;
  707.       do
  708.      keyword_count := keyword.count;
  709.      from
  710.         start_line := line;
  711.         start_column := column;
  712.      until
  713.         i = keyword_count or else not cc.same_as(keyword.item(i+1))
  714.      loop
  715.         i := i + 1;
  716.         next_char;
  717.      end;
  718.      if i = keyword_count then
  719.         inspect 
  720.            cc
  721.         when ' ','%N','%T','-' then
  722.            Result := true;
  723.            last_keyword := keyword;
  724.            skip_comments;
  725.         when 'a'..'z','A'..'Z','0'..'9','_' then
  726.            from  
  727.            until
  728.           i = 0
  729.            loop
  730.           prev_char;
  731.           i := i - 1;
  732.            end;
  733.         else
  734.            Result := true;
  735.            last_keyword := keyword;
  736.         end;
  737.      else
  738.         from  
  739.         until
  740.            i = 0
  741.         loop
  742.            prev_char;
  743.            i := i - 1;
  744.         end;
  745.      end;
  746.       end;
  747.    
  748.    a_ascii_code is
  749.      -- To read a character given as an ascii code in a manifest 
  750.      -- constant CHARACTER or STRING;
  751.      -- Require/Ensure : cc = '/'.
  752.       local
  753.      counter: INTEGER;
  754.       do
  755.      from  
  756.         check
  757.            cc = '/'
  758.         end;
  759.         next_char;
  760.         counter := 0;
  761.         last_ascii_code := 0;
  762.      until
  763.         counter > 3 or else cc = '/'
  764.      loop
  765.         inspect 
  766.            cc
  767.         when '0' .. '9' then
  768.            last_ascii_code := last_ascii_code * 10 + cc.value;
  769.         else
  770.            fcp("Unexpected character in ascii code.");
  771.         end;
  772.         counter := counter + 1;
  773.         next_char;
  774.      end;
  775.      if counter = 0 then
  776.         fcp("Bad (empty ?) ascii code.");
  777.      elseif counter > 3 then
  778.         fcp("Three digit is enought for an ascii code.");
  779.      else
  780.         check
  781.            cc = '/'
  782.         end;
  783.      end;
  784.       end;
  785.    
  786. feature {NONE} ----------------------------------------------------------------
  787.    -- Very VERY low level character and text manipulation.
  788.    
  789.    go_back(p: POSITION) is
  790.      -- Go back to `p'.
  791.       do
  792.      go_back_at(p.line,p.column);
  793.       end; 
  794.    
  795.    go_back_at(l, c: INTEGER) is
  796.      -- Go back to `l',`c'.
  797.       do
  798.      line := l;
  799.      column := c;
  800.      current_line := parser_buffer.item(line);
  801.      if column = current_line.count + 1 then
  802.         cc := '%N';
  803.      elseif column = 0 then
  804.         cc := '%U';
  805.      else
  806.         cc := current_line.item(column);
  807.      end;
  808.       end; 
  809.    
  810.    next_char is
  811.       do
  812.      if column < current_line.count then
  813.         column := column + 1;
  814.         cc := current_line.item(column);
  815.      elseif column = current_line.count then
  816.         column := column + 1;
  817.         cc := '%N';
  818.      elseif line = parser_buffer.count then
  819.         cc := end_of_text;
  820.      else
  821.         column := 1;
  822.         line := line + 1;
  823.         current_line := parser_buffer.item(line);
  824.         if current_line.count = 0 then
  825.            cc := '%N';
  826.         else
  827.            cc := current_line.first;
  828.         end;
  829.      end;
  830.       end; 
  831.    
  832.    prev_char is
  833.       do
  834.      if column > 1 then
  835.         column := column - 1;
  836.         cc := current_line.item(column);
  837.      else -- column = 1
  838.         if line > 1 then
  839.            line := line -1;
  840.            current_line := parser_buffer.item(line);
  841.            column := current_line.count + 1;
  842.            cc := '%N';
  843.         else
  844.            column := 0;
  845.            cc := '%U';
  846.         end;
  847.      end;
  848.       end;
  849.    
  850.    skip1(char: CHARACTER): BOOLEAN is
  851.       do
  852.      if char = cc then
  853.         start_line := line;
  854.         start_column := column;
  855.         Result := true;
  856.         next_char;
  857.         skip_comments;
  858.      end;
  859.       end;
  860.       
  861.    skip2(c1, c2: CHARACTER): BOOLEAN is
  862.       do
  863.      if c1 = cc then
  864.         start_line := line;
  865.         start_column := column;
  866.         next_char;
  867.         if c2 = cc then
  868.            Result := true;
  869.            next_char;
  870.            skip_comments;
  871.         else
  872.            prev_char;
  873.         end;
  874.      end;
  875.       end;
  876.    
  877.    skip1unless2(c1, c2: CHARACTER): BOOLEAN is
  878.       do
  879.      start_line := line;
  880.      start_column := column;
  881.      if cc = c1 then
  882.         next_char;
  883.         if cc = c2 then
  884.            prev_char;
  885.         else
  886.            Result := true;
  887.            skip_comments;
  888.         end;
  889.      end;
  890.       end;
  891.    
  892.    skip_comments is
  893.      -- Skip separators and store comments in `last_comments'.
  894.       local
  895.      sp: POSITION;
  896.      state: INTEGER;
  897.      -- state 0 : nothing read.
  898.      -- state 1 : first '-' read.
  899.      -- state 2 : end.
  900.       do
  901.      from  
  902.      until
  903.         state = 2
  904.      loop
  905.         inspect         
  906.            state
  907.         when 0 then
  908.            inspect 
  909.           cc
  910.            when ' ','%T','%N' then
  911.           next_char;
  912.            when '-' then
  913.           next_char;
  914.           state := 1;
  915.            else 
  916.           state := 2;
  917.            end;
  918.         when 1 then
  919.            inspect 
  920.           cc
  921.            when '-' then
  922.           from  
  923.              if drop_comments then
  924.              else 
  925.             if last_comments = Void then
  926.                !!sp.make(line,column - 1);
  927.             end;
  928.              end;
  929.              next_char;
  930.              lcs.clear;
  931.           until
  932.              cc = '%N'
  933.           loop
  934.              lcs.extend(cc);
  935.              next_char;
  936.           end;
  937.           if drop_comments then
  938.           else
  939.              if last_comments = Void then
  940.             !!last_comments.make(sp,<<(lcs.twin)>>);
  941.              else
  942.             last_comments.add_last(lcs.twin);
  943.              end;
  944.           end;
  945.           state := 0;
  946.            else
  947.           prev_char;
  948.           state := 2;
  949.            end;
  950.         end;
  951.      end;
  952.       end;
  953.    
  954. feature {NONE} ----------------------------------------------------------------
  955.    -- Lexicographic level.
  956.    
  957.    a_bit_constant: BOOLEAN is
  958.       local
  959.      l, c, state: INTEGER;
  960.      -- state 0 : first bit read.
  961.      -- state 1 : happy end.
  962.      -- state 2 : error end.
  963.       do
  964.      if cc = '0' or else cc = '1' then
  965.         from
  966.            l := line;
  967.            c := column;
  968.            tmp_string.clear;
  969.            tmp_string.extend(cc);
  970.         until
  971.            state > 0
  972.         loop
  973.            next_char;
  974.            inspect 
  975.           cc
  976.            when '0','1' then
  977.           tmp_string.extend(cc);
  978.            when 'b','B' then
  979.           !!last_bit_constant.make(pos(l,c),tmp_string.twin);
  980.           next_char;
  981.           skip_comments;
  982.           state := 1;
  983.           Result := true;
  984.            else
  985.           go_back_at(l,c);
  986.           state := 2;
  987.            end;
  988.         end;
  989.      end;   
  990.       end;
  991.       
  992.    a_character_constant: BOOLEAN is
  993.       local
  994.      sp: POSITION;
  995.      state, printing_mode: INTEGER;
  996.      value: CHARACTER;
  997.      -- state 0 : first '%'' read.
  998.      -- state 1 : first '%%' read.
  999.      -- state 2 : wait for second '%''.
  1000.      -- state 3 : happy end.
  1001.       do
  1002.      if cc = '%'' then
  1003.         from  
  1004.            !!sp.make(line,column);
  1005.            Result := true;
  1006.         until
  1007.            state > 2
  1008.         loop
  1009.            next_char;
  1010.            inspect 
  1011.           state
  1012.            when 0 then
  1013.           inspect 
  1014.              cc
  1015.           when '%%' then
  1016.              state := 1;
  1017.           when '%'' then
  1018.              fcp(em10);
  1019.              state := 2;
  1020.           else
  1021.              value := cc;
  1022.              printing_mode := 0;
  1023.              state := 2;
  1024.           end;
  1025.            when 1 then
  1026.           printing_mode := 1;
  1027.           state := 2;
  1028.           inspect
  1029.              cc
  1030.           when 'A' then
  1031.              value := '%A';
  1032.           when 'B' then
  1033.              value := '%B';
  1034.           when 'C' then
  1035.              value := '%C';
  1036.           when 'D' then
  1037.              value := '%D';
  1038.           when 'F' then
  1039.              value := '%F';
  1040.           when 'H' then
  1041.              value := '%H';
  1042.           when 'L' then
  1043.              value := '%L';
  1044.           when 'N' then
  1045.              value := '%N';
  1046.           when 'Q' then
  1047.              value := '%Q';
  1048.           when 'R' then
  1049.              value := '%R';
  1050.           when 'S' then
  1051.              value := '%S';
  1052.           when 'T' then
  1053.              value := '%T';
  1054.           when 'U' then
  1055.              value := '%U';
  1056.           when 'V' then
  1057.              value := '%V';
  1058.           when '%%' then
  1059.              value := '%%';
  1060.           when '%'' then
  1061.              value := '%'';
  1062.           when '%"' then
  1063.              value := '%"';
  1064.           when '(' then
  1065.              value := '%(';
  1066.           when ')' then
  1067.              value := '%)';
  1068.           when '<' then
  1069.              value := '%<';
  1070.           when '>' then
  1071.              value := '%>';
  1072.           when '/' then
  1073.              a_ascii_code;
  1074.              value := last_ascii_code.to_character;
  1075.              printing_mode := 2;
  1076.           else
  1077.              fcp("Unknown special character.");
  1078.           end;
  1079.            else -- state = 2
  1080.           state := 3;
  1081.           inspect 
  1082.              cc
  1083.           when '%'' then
  1084.           else
  1085.              fcp(em10);
  1086.           end;
  1087.           next_char;
  1088.           skip_comments;
  1089.            end;
  1090.         end;
  1091.         !!last_character_constant.make(sp,value,printing_mode);
  1092.      end;
  1093.       end;
  1094.    
  1095.    a_constant: BOOLEAN is
  1096.       -- Only true for constant allowed in "when of inspect".
  1097.       local
  1098.      implicit_current: IMPLICIT_CURRENT;
  1099.      sfn: SIMPLE_FEATURE_NAME;
  1100.       do
  1101.      if a_identifier then
  1102.         Result := true;
  1103.         sfn := tmp_name.to_simple_feature_name;
  1104.         !!implicit_current.make(sfn.start_position);
  1105.         !CALL_0_C!last_expression.make(implicit_current,sfn);
  1106.      elseif a_character_constant then
  1107.         Result := true;
  1108.         last_expression := last_character_constant;
  1109.      elseif a_integer_constant then
  1110.         Result := true;
  1111.         last_expression := last_integer_constant;
  1112.      end;
  1113.       end;
  1114.    
  1115.    a_base_class_name: BOOLEAN is
  1116.       local
  1117.      state: INTEGER;
  1118.      do_warning: BOOLEAN;
  1119.      -- state 0 : first letter read.
  1120.      -- state 1 : end.
  1121.       do
  1122.      if cc.is_letter then
  1123.         from
  1124.            if cc >= 'a' then
  1125.           do_warning := true;
  1126.           cc := cc.to_upper;
  1127.            end;
  1128.            tmp_name.initialize(line,column);
  1129.            tmp_name.extend(cc);
  1130.         until
  1131.            state > 0
  1132.         loop
  1133.            next_char;
  1134.            inspect
  1135.           cc
  1136.            when 'A'..'Z','0'..'9','_' then
  1137.           tmp_name.extend(cc);
  1138.            when 'a'..'z' then
  1139.           do_warning := true;
  1140.           tmp_name.extend(cc.to_upper);
  1141.            else
  1142.           state := 1;
  1143.            end;
  1144.         end;
  1145.         if tmp_name.isa_keyword then
  1146.            from  
  1147.           state := tmp_name.count;
  1148.            until
  1149.           state = 0
  1150.            loop
  1151.           state := state - 1;
  1152.           prev_char;
  1153.            end;
  1154.         else
  1155.            Result := true;
  1156.            skip_comments;
  1157.            if do_warning then
  1158.           warning(tmp_name.start_position,em15);
  1159.            end;
  1160.            last_class_name := tmp_name.to_class_name;
  1161.         end;
  1162.      end;
  1163.       end;
  1164.    
  1165.    a_base_class_name1 is
  1166.      -- Read the current base class name.
  1167.       local
  1168.      state: INTEGER;
  1169.      do_warning: BOOLEAN;
  1170.      ccn: CLASS_NAME;
  1171.      -- state 0 : first letter read.
  1172.      -- state 1 : end.
  1173.       do
  1174.      ccn := last_base_class.name;
  1175.      if cc.is_letter then
  1176.         from
  1177.            ccn.start_position.set_line_column(line,column);
  1178.            tmp_name.initialize(line,column);
  1179.            if cc >= 'a' then
  1180.           do_warning := true;
  1181.           cc := cc.to_upper;
  1182.            end;
  1183.            tmp_name.extend(cc);
  1184.         until
  1185.            state > 0
  1186.         loop
  1187.            next_char;
  1188.            inspect
  1189.           cc
  1190.            when 'A'..'Z','0'..'9','_' then
  1191.           tmp_name.extend(cc);
  1192.            when 'a'..'z' then
  1193.           do_warning := true;
  1194.           tmp_name.extend(cc.to_upper);
  1195.            else
  1196.           state := 1;
  1197.            end;
  1198.         end;
  1199.         skip_comments;
  1200.         if tmp_name.isa_keyword then
  1201.            eh.add_position(ccn.start_position);
  1202.            fatal_error(em16);
  1203.         end;
  1204.         if do_warning then
  1205.            warning(ccn.start_position,em15);
  1206.         end;
  1207.         ccn.identify(tmp_name.to_string);
  1208.      else
  1209.         fcp(em16);
  1210.      end;
  1211.      if forbidden_class.fast_has(ccn.to_string) then
  1212.         eh.add_position(ccn.start_position);
  1213.         fatal_error("Cannot write such a class.");
  1214.      end;
  1215.       end;
  1216.  
  1217.    a_type_formal_generic: BOOLEAN is
  1218.       local
  1219.      fga: FORMAL_GENERIC_ARG;
  1220.      cn: CLASS_NAME;
  1221.      rank: INTEGER;
  1222.       do
  1223.      if formal_generic_list /= Void then
  1224.         from  
  1225.            rank := 1;
  1226.         until
  1227.            Result or else rank > formal_generic_list.count
  1228.         loop
  1229.            fga := formal_generic_list.item(rank);
  1230.            if a_keyword(fga.name.to_string) then
  1231.           !!cn.make(fga.name.to_string,pos(start_line,start_column));
  1232.           !!last_type_formal_generic.make(cn,rank);
  1233.           Result := true;
  1234.            end;
  1235.            rank := rank + 1;
  1236.         end;        
  1237.      end;
  1238.       end;
  1239.    
  1240.    a_free_operator: BOOLEAN is
  1241.      --++ free_operator -> "@..." |
  1242.      --++                  "#..." |
  1243.      --++                  "|..." |
  1244.      --++                  "&..."
  1245.      --++                
  1246.       do
  1247.      if (cc = '@') or else 
  1248.         (cc = '#') or else
  1249.         (cc = '|') or else
  1250.         (cc = '&') then
  1251.         Result := true;
  1252.         from  
  1253.            tmp_name.initialize(line,column);
  1254.            tmp_name.extend(cc);
  1255.            next_char;
  1256.         until
  1257.            (cc = '%N') or else
  1258.            (cc = ' ') or else
  1259.            (cc = '%T') or else
  1260.            (cc = '%"')
  1261.         loop
  1262.            tmp_name.extend(cc);
  1263.            next_char;
  1264.         end;
  1265.         skip_comments;
  1266.      end;
  1267.       end;
  1268.    
  1269.    a_identifier: BOOLEAN is
  1270.       do
  1271.      if case_insensitive then
  1272.         Result := a_identifier1;
  1273.      else
  1274.         Result := a_identifier2;
  1275.      end;
  1276.       end;
  1277.  
  1278.    a_integer: BOOLEAN is
  1279.       local
  1280.      state, value: INTEGER;
  1281.      -- state 0 : 1st digit read (no '_' encountered).
  1282.      -- state 1 : 2nd digit read (no '_' encountered).
  1283.      -- state 2 : 3rd digit read (no '_' encountered).
  1284.      -- state 3 : more than 3 digit read (no '_' encountered).
  1285.      -- state 4 : after '_'.
  1286.      -- state 5 : after '_' and 1 digit read.
  1287.      -- state 6 : after '_' and 2 digit read.
  1288.      -- state 7 : after '_' and 3 digit read.
  1289.      -- state 8 : satisfaction state.
  1290.       do
  1291.      if cc.is_digit then
  1292.         from  
  1293.            Result := true;
  1294.            start_line := line;
  1295.            start_column := column;
  1296.            value := cc.value;
  1297.         until
  1298.            state > 7
  1299.         loop
  1300.            next_char;
  1301.            inspect 
  1302.           state
  1303.            when 0 then
  1304.           inspect 
  1305.              cc
  1306.           when '0'..'9' then
  1307.              value := value * 10 + cc.value;
  1308.              state := 1;
  1309.           when '_' then
  1310.              state := 4;
  1311.           else
  1312.              state := 8;
  1313.           end;
  1314.            when 1 then
  1315.           inspect 
  1316.              cc
  1317.           when '0'..'9' then
  1318.              value := value * 10 + cc.value;
  1319.              state := 2;
  1320.           when '_' then
  1321.              state := 4;
  1322.           else
  1323.              state := 8;
  1324.           end;
  1325.            when 2 then
  1326.           inspect 
  1327.              cc
  1328.           when '0'..'9' then
  1329.              value := value * 10 + cc.value;
  1330.              state := 3;
  1331.           when '_' then
  1332.              state := 4;
  1333.           else
  1334.              state := 8;
  1335.           end;
  1336.            when 3 then
  1337.           inspect 
  1338.              cc
  1339.           when '0'..'9' then
  1340.              value := value * 10 + cc.value;
  1341.           when '_' then
  1342.              fcp(em9);
  1343.           else
  1344.              state := 8;
  1345.           end;
  1346.            when 4 then
  1347.           inspect 
  1348.              cc
  1349.           when '0'..'9' then
  1350.              value := value * 10 + cc.value;
  1351.              state := 5;
  1352.           else
  1353.              fcp(em9);
  1354.           end;
  1355.            when 5 then
  1356.           inspect 
  1357.              cc
  1358.           when '0'..'9' then
  1359.              value := value * 10 + cc.value;
  1360.              state := 6;
  1361.           else
  1362.              fcp(em9);
  1363.           end;
  1364.            when 6 then
  1365.           inspect 
  1366.              cc
  1367.           when '0'..'9' then
  1368.              value := value * 10 + cc.value;
  1369.              state := 7;
  1370.           else
  1371.              fcp(em9);
  1372.           end;
  1373.            when 7 then
  1374.           inspect 
  1375.              cc
  1376.           when '0'..'9' then
  1377.              fcp(em9);
  1378.           when '_' then
  1379.              state := 4;
  1380.           else
  1381.              state := 8;
  1382.           end;
  1383.            end;
  1384.         end;
  1385.         if cc.is_letter then
  1386.            fcp(em20);
  1387.         end;
  1388.         skip_comments;
  1389.         !!last_integer_constant.make(value,pos(start_line,start_column));
  1390.      end;
  1391.       end;
  1392.    
  1393.    a_manifest_string: BOOLEAN is
  1394.       local
  1395.      state: INTEGER;
  1396.      -- state 0 : inside string.
  1397.      -- state 1 : just read a '%%'.
  1398.      -- state 2 : extended form starting (waiting for '%N').
  1399.      -- state 3 : extended form ending (waiting for '%%').
  1400.      -- state 4 : happy end.
  1401.       do
  1402.      if cc = '%"' then
  1403.         from  
  1404.            Result := true;
  1405.            !!last_manifest_string.make(pos(line,column));
  1406.         until
  1407.            state > 3
  1408.         loop
  1409.            next_char;
  1410.            inspect 
  1411.           state
  1412.            when 0 then
  1413.           inspect 
  1414.              cc
  1415.           when '%N' then
  1416.              fcp(em8);
  1417.           when '%"' then
  1418.              state := 4;
  1419.           when '%%' then
  1420.              state := 1;
  1421.           else
  1422.              last_manifest_string.add(cc);
  1423.           end;
  1424.            when 1 then
  1425.           state := 0;
  1426.           inspect 
  1427.              cc
  1428.           when '%N' then
  1429.              state := 3;
  1430.           when 'A' then
  1431.              last_manifest_string.add_percent('%A');
  1432.           when 'B' then
  1433.              last_manifest_string.add_percent('%B');
  1434.           when 'C' then
  1435.              last_manifest_string.add_percent('%C');
  1436.           when 'D' then
  1437.              last_manifest_string.add_percent('%D');
  1438.           when 'F' then
  1439.              last_manifest_string.add_percent('%F');
  1440.           when 'H' then
  1441.              last_manifest_string.add_percent('%H');
  1442.           when 'L' then
  1443.              last_manifest_string.add_percent('%L');
  1444.           when 'N' then
  1445.              last_manifest_string.add_percent('%N');
  1446.           when 'Q' then
  1447.              last_manifest_string.add_percent('%Q');
  1448.           when 'R' then
  1449.              last_manifest_string.add_percent('%R');
  1450.           when 'S' then
  1451.              last_manifest_string.add_percent('%S');
  1452.           when 'T' then
  1453.              last_manifest_string.add_percent('%T');
  1454.           when 'U' then
  1455.              last_manifest_string.add_percent('%U');
  1456.           when 'V' then
  1457.              last_manifest_string.add_percent('%V');
  1458.           when '%%' then
  1459.              last_manifest_string.add_percent('%%');
  1460.           when '%'' then
  1461.              last_manifest_string.add_percent('%'');
  1462.           when '%"' then
  1463.              last_manifest_string.add_percent('%"');
  1464.           when '(' then
  1465.              last_manifest_string.add_percent('%(');
  1466.           when ')' then
  1467.              last_manifest_string.add_percent('%)');
  1468.           when '<' then
  1469.              last_manifest_string.add_percent('%<');
  1470.           when '>' then
  1471.              last_manifest_string.add_percent('%>');
  1472.           when '/' then
  1473.              a_ascii_code;
  1474.              last_manifest_string.add_ascii(last_ascii_code.to_character);
  1475.           when ' ','%T' then
  1476.              state := 2;
  1477.           else
  1478.              fcp("Unknown special character.");
  1479.              state := 0;
  1480.           end;
  1481.            when 2 then
  1482.           inspect 
  1483.              cc
  1484.           when '%N' then
  1485.              state := 3;
  1486.           when ' ','%T' then
  1487.           else
  1488.              fcp("In extended form of manifest string.%
  1489.              %Bad character after '%%'.");
  1490.           end;
  1491.            else -- state = 3
  1492.           inspect 
  1493.              cc
  1494.           when ' ','%T' then
  1495.           when '%%' then
  1496.              last_manifest_string.break_line;
  1497.              state := 0;
  1498.           when '%N' then
  1499.              fcp(em8);
  1500.              state := 0;
  1501.           else 
  1502.              fcp("In extended form of manifest string.%
  1503.              % Bad character before '%%'.");
  1504.              state := 0;
  1505.           end;
  1506.            end;
  1507.         end;        
  1508.         next_char;
  1509.         skip_comments;
  1510.      end;
  1511.       end;
  1512.    
  1513.    a_real: BOOLEAN is
  1514.       local
  1515.      state, l, c: INTEGER;
  1516.      -- state 0  : reading integral part.
  1517.      -- state 1  : reading integral part after '_'.
  1518.      -- state 2  : reading integral part after '_' and 1 digit.
  1519.      -- state 3  : reading integral part after '_' and 2 digits.
  1520.      -- state 4  : '.' read and not empty integral_part.
  1521.      -- state 5  : '.' read and empty integral_part.
  1522.      -- state 6  : reading frac_part.
  1523.      -- state 7  : reading frac_part after '_'.
  1524.      -- state 8  : reading frac_part after '_' and 1 digit.
  1525.      -- state 9  : reading frac_part after '_' and 2 digits.
  1526.      -- state 10 : 'E' or 'e' read.
  1527.      -- state 11 : reading exponent.
  1528.      -- state 12 : happy end.
  1529.      -- state 13 : error end.
  1530.       do
  1531.      if cc.is_digit or else cc = '.' then
  1532.         from
  1533.            l := line;
  1534.            c := column;
  1535.            tmp_string.clear;
  1536.            if cc = '.' then
  1537.           tmp_string.append(fz_59);
  1538.           state := 5;
  1539.            else
  1540.           tmp_string.extend(cc);
  1541.            end;
  1542.         until
  1543.            state > 11
  1544.         loop
  1545.            next_char;
  1546.            inspect 
  1547.           state
  1548.            when 0 then
  1549.           inspect 
  1550.              cc
  1551.           when '0' .. '9' then
  1552.              tmp_string.extend(cc);
  1553.           when '.' then
  1554.              tmp_string.extend('.');
  1555.              state := 4;
  1556.           else
  1557.              state := 13;
  1558.           end;
  1559.            when 1 then
  1560.           inspect 
  1561.              cc
  1562.           when '0'..'9' then
  1563.              tmp_string.extend(cc);
  1564.              state := 2;
  1565.           else
  1566.              fcp(em9);
  1567.           end;
  1568.            when 2 then
  1569.           inspect 
  1570.              cc
  1571.           when '0'..'9' then
  1572.              tmp_string.extend(cc);
  1573.              state := 3;
  1574.           else
  1575.              fcp(em9);
  1576.           end;
  1577.            when 3 then
  1578.           inspect 
  1579.              cc
  1580.           when '0'..'9' then
  1581.              tmp_string.extend(cc);
  1582.              state := 0;
  1583.           else
  1584.              fcp(em9);
  1585.           end;
  1586.            when 4 then
  1587.           inspect 
  1588.              cc
  1589.           when '0'..'9' then
  1590.              tmp_string.extend(cc);
  1591.              state := 6;
  1592.           when 'E','e' then
  1593.              tmp_string.extend('E');
  1594.              state := 10;
  1595.           else
  1596.              state := 12;
  1597.           end;
  1598.            when 5 then
  1599.           inspect 
  1600.              cc
  1601.           when '0'..'9' then
  1602.              tmp_string.extend(cc);
  1603.              state := 6;
  1604.           else
  1605.              state := 13;
  1606.           end;
  1607.            when 6 then
  1608.           inspect 
  1609.              cc
  1610.           when '0'..'9' then
  1611.              tmp_string.extend(cc);
  1612.           when 'E','e' then
  1613.              tmp_string.extend('E');
  1614.              state := 10;
  1615.           when '_' then
  1616.              state := 7;
  1617.           else
  1618.              state := 12;
  1619.           end;
  1620.            when 7 then
  1621.           inspect 
  1622.              cc
  1623.           when '0'..'9' then
  1624.              tmp_string.extend(cc);
  1625.              state := 8;
  1626.           else
  1627.              fcp(em1);
  1628.           end;
  1629.            when 8 then
  1630.           inspect 
  1631.              cc
  1632.           when '0'..'9' then
  1633.              tmp_string.extend(cc);
  1634.              state := 9;
  1635.           else
  1636.              fcp(em1);
  1637.           end;
  1638.            when 9 then
  1639.           inspect 
  1640.              cc
  1641.           when '0'..'9' then
  1642.              tmp_string.extend(cc);
  1643.              state := 6;
  1644.           else
  1645.              fcp(em1);
  1646.           end;
  1647.            when 10 then
  1648.           inspect 
  1649.              cc
  1650.           when '+' then
  1651.              state := 11;
  1652.           when '-' then
  1653.              tmp_string.extend('-');
  1654.              state := 11;
  1655.           when '0'..'9' then
  1656.              tmp_string.extend(cc);
  1657.              state := 11
  1658.           else
  1659.              fcp("Exponent of a real value expected.");
  1660.              state := 13;
  1661.           end;
  1662.            else -- state = 11
  1663.           inspect 
  1664.              cc
  1665.           when '0'..'9' then
  1666.              tmp_string.extend(cc);
  1667.           else
  1668.              state := 12;
  1669.           end;
  1670.            end;
  1671.         end;        
  1672.         if state = 12 then
  1673.            !!last_real_constant.make(pos(l,c),tmp_string.twin);
  1674.            Result := true;
  1675.            skip_comments;
  1676.         else
  1677.            go_back_at(l,c);
  1678.         end;
  1679.      end;
  1680.       end;
  1681.    
  1682.    a_retry: BOOLEAN is
  1683.       do
  1684.      if a_keyword(fz_retry) then
  1685.         if not in_rescue then
  1686.            error(pos(start_line,start_column),
  1687.               "%"retry%" cannot be outside of a rescue clause."); 
  1688.         end;
  1689.         !E_RETRY!last_instruction.make(pos(start_line,start_column));
  1690.         Result := true;
  1691.      end;
  1692.       end;
  1693.    
  1694. feature {NONE} ----------------------------------------------------------------- 
  1695.    -- Syntax analysis (recursive descent).
  1696.    -- Rules are in alphabetic order.
  1697.    -- 
  1698.    
  1699.    a_actual: BOOLEAN is
  1700.      --++ actual -> expression |
  1701.      --++           "$" identifier
  1702.      --++
  1703.       do
  1704.      if skip1('%D') then
  1705.         if a_identifier then
  1706.            if a_result or else a_void or else a_current then
  1707.           eh.add_position(last_expression.start_position);
  1708.           fatal_error(em17);
  1709.            else
  1710.           !ADDRESS_OF!last_expression.make(tmp_name.to_simple_feature_name);
  1711.           Result:= true;
  1712.            end;
  1713.         else
  1714.            fcp(em17);
  1715.         end;
  1716.      elseif a_expression then
  1717.         Result := true;
  1718.      end;
  1719.       end;
  1720.    
  1721.    a_actuals: EFFECTIVE_ARG_LIST is
  1722.      --++ actuals -> "(" {actual "," ...} ")"
  1723.      --++
  1724.       local
  1725.      first_one: EXPRESSION;
  1726.      remainder: FIXED_ARRAY[EXPRESSION];
  1727.       do
  1728.      if skip1('(') then
  1729.         from        
  1730.         until
  1731.            not a_actual
  1732.         loop
  1733.            if first_one = Void then
  1734.           first_one := last_expression;
  1735.            else
  1736.           if remainder = Void then
  1737.              !!remainder.with_capacity(4);
  1738.           end;
  1739.           remainder.add_last(last_expression);
  1740.            end;
  1741.            if not skip1(',') and then cc /= ')' then
  1742.           wcp(em5);
  1743.            end;
  1744.         end;
  1745.         if first_one = Void then
  1746.            wcp("Empty argument list (deleted).");
  1747.         else
  1748.            !!Result.make_n(first_one,remainder);
  1749.         end;
  1750.         if not skip1(')') then
  1751.            fcp("')' expected to end arguments list.");
  1752.         end;
  1753.      end;
  1754.       end;
  1755.    
  1756.    a_after_a_dot(do_instruction: BOOLEAN; target: EXPRESSION) is
  1757.      --++ after_a_dot -> identifier [actuals] ["." after_a_dot]
  1758.      --++
  1759.       require      
  1760.      target /= Void
  1761.       local
  1762.      sfn: SIMPLE_FEATURE_NAME;
  1763.      eal: EFFECTIVE_ARG_LIST;
  1764.       do
  1765.      if a_identifier then
  1766.         if a_result or else a_void or else a_current 
  1767.          then
  1768.            eh.add_position(last_expression.start_position);
  1769.            eh.error("This name must not appear after a dot.");
  1770.         end;
  1771.         sfn := tmp_name.to_simple_feature_name;
  1772.         eal := a_actuals;
  1773.         a_r10(do_instruction,target,sfn,eal);
  1774.      else
  1775.         fcp("Identifier expected after a dot.");
  1776.      end;
  1777.       end;
  1778.    
  1779.    a_assignment_or_call: BOOLEAN is
  1780.      --++ assignment_or_call -> "(" expression ")" r10 |
  1781.      --++                       precursor_call |
  1782.      --++                       "Current" r10 |
  1783.      --++                       "Result" r10 |
  1784.      --++                       local_variable r10 |
  1785.      --++                       formal_argument r10 |
  1786.      --++                       writable ":=" expression | 
  1787.      --++                       writable "?=" expression |
  1788.      --++                       identifier procedure_call
  1789.      --++
  1790.       do
  1791.      if skip1('(') and then a_expression then
  1792.         Result := true;
  1793.         if skip1(')') then
  1794.            a_r10(true,last_expression,Void,Void);
  1795.         else
  1796.            fcp("')' expected.");
  1797.         end;
  1798.      elseif a_precursor(true) then
  1799.             Result := true;
  1800.      elseif a_identifier then
  1801.         Result := true;
  1802.         if skip2(':','=') then
  1803.            a_assignment_aux(true);
  1804.         elseif skip2('?','=') then
  1805.            a_assignment_aux(false);
  1806.         elseif a_current or else a_result or else a_local_variable 
  1807.            or else a_argument then
  1808.            a_r10(true,last_expression,Void,Void);
  1809.         else   
  1810.            a_procedure_call;
  1811.         end;
  1812.      end;
  1813.       end;
  1814.    
  1815.    a_assignment_aux(regular: BOOLEAN) is
  1816.       local
  1817.      writable, rhs: EXPRESSION;
  1818.       do
  1819.      if a_current then
  1820.         eh.add_position(last_expression.start_position);
  1821.         fatal_error("Must not affect `Current'.");
  1822.      elseif a_void then
  1823.         eh.add_position(tmp_name.start_position);
  1824.         fatal_error("Must not affect `Void'.");
  1825.      elseif a_argument then
  1826.         eh.add_position(last_expression.start_position);
  1827.         fatal_error("Must not affect a formal argument.");
  1828.      else
  1829.         if tmp_name.is_result then
  1830.            writable := last_result;
  1831.         elseif a_local_variable then
  1832.            writable := last_expression;
  1833.         else
  1834.            writable := tmp_name.to_simple_feature_name;
  1835.         end;
  1836.         if a_expression then
  1837.            rhs := last_expression;
  1838.            if regular then
  1839.           !ASSIGNMENT!last_instruction.make(writable,rhs);
  1840.            else
  1841.           !REVERSE_ASSIGNMENT!last_instruction.make(writable,rhs);
  1842.            end;
  1843.         else
  1844.            fcp("Right hand side expression expected for assignment.");
  1845.         end;
  1846.      end;
  1847.       end;
  1848.    
  1849.    a_assertion: ARRAY[ASSERTION] is
  1850.      --++ assertion -> {assertion_clause ";" ...}
  1851.      --++ assertion_clause -> [identifier ":"] [expression] [comment]
  1852.      --++
  1853.       local
  1854.      tag: like last_tag_mark;
  1855.      expression: like last_expression;
  1856.      assertion: ASSERTION;
  1857.      state: INTEGER;
  1858.      -- state 0 : nothing read.
  1859.      -- state 1 : read a `tag'.
  1860.      -- state 2 : read an `expression'.
  1861.      -- state 3 : read a `tag' and an `expression'.
  1862.      -- state 4 : end;
  1863.       do
  1864.      from
  1865.      until
  1866.         state > 3
  1867.      loop
  1868.         inspect 
  1869.            state
  1870.         when 0 then
  1871.            if cc = ';' then
  1872.           wcp(fz_desc);
  1873.           ok := skip1(';');
  1874.           if last_comments /= Void then
  1875.              !!assertion.make(Void,Void,get_comments);
  1876.              if Result = Void then
  1877.             Result := <<assertion>>;
  1878.              else
  1879.             Result.add_last(assertion);
  1880.              end;
  1881.           end;
  1882.            elseif a_tag_mark then
  1883.           tag := last_tag_mark;
  1884.           state := 1;
  1885.            elseif a_expression then          
  1886.           expression := last_expression;
  1887.           state := 2;
  1888.            else
  1889.           state := 4;
  1890.            end;
  1891.         when 1 then
  1892.            if skip1(';') then
  1893.           !!assertion.make(tag,Void,get_comments);
  1894.           if Result = Void then
  1895.              Result := <<assertion>>;
  1896.           else
  1897.              Result.add_last(assertion);
  1898.           end;
  1899.           state := 0;
  1900.            elseif a_tag_mark then
  1901.           !!assertion.make(tag,Void,get_comments);
  1902.           if Result = Void then
  1903.              Result := <<assertion>>;
  1904.           else
  1905.              Result.add_last(assertion);
  1906.           end;
  1907.           tag := last_tag_mark;
  1908.            elseif a_expression then
  1909.           expression := last_expression;
  1910.           state := 3;
  1911.            else
  1912.           !!assertion.make(tag,Void,get_comments);
  1913.           if Result = Void then
  1914.              Result := <<assertion>>;
  1915.           else
  1916.              Result.add_last(assertion);
  1917.           end;
  1918.           state := 4;
  1919.            end;
  1920.         when 2 then
  1921.            if skip1(';') then
  1922.           !!assertion.make(Void,expression,get_comments);
  1923.           if Result = Void then
  1924.              Result := <<assertion>>;
  1925.           else
  1926.              Result.add_last(assertion);
  1927.           end;
  1928.           state := 0;
  1929.            elseif a_tag_mark then
  1930.           !!assertion.make(Void,expression,get_comments);
  1931.           if Result = Void then
  1932.              Result := <<assertion>>;
  1933.           else
  1934.              Result.add_last(assertion);
  1935.           end;
  1936.           tag := last_tag_mark;
  1937.           state := 1;
  1938.            elseif a_expression then
  1939.           !!assertion.make(Void,expression,get_comments);
  1940.           if Result = Void then
  1941.              Result := <<assertion>>;
  1942.           else
  1943.              Result.add_last(assertion);
  1944.           end;
  1945.           expression := last_expression;
  1946.           state := 2;
  1947.            else
  1948.           !!assertion.make(Void,expression,get_comments);
  1949.           if Result = Void then
  1950.              Result := <<assertion>>;
  1951.           else
  1952.              Result.add_last(assertion);
  1953.           end;
  1954.           state := 4;
  1955.            end;
  1956.         else -- state = 3
  1957.            if skip1(';') then
  1958.           !!assertion.make(tag,expression,get_comments);
  1959.           if Result = Void then
  1960.              Result := <<assertion>>;
  1961.           else
  1962.              Result.add_last(assertion);
  1963.           end;
  1964.           state := 0;
  1965.            elseif a_tag_mark then
  1966.           !!assertion.make(tag,expression,get_comments);
  1967.           if Result = Void then
  1968.              Result := <<assertion>>;
  1969.           else
  1970.              Result.add_last(assertion);
  1971.           end;
  1972.           tag := last_tag_mark;
  1973.           state := 1;
  1974.            elseif a_expression then
  1975.           !!assertion.make(tag,expression,get_comments);
  1976.           if Result = Void then
  1977.              Result := <<assertion>>;
  1978.           else
  1979.              Result.add_last(assertion);
  1980.           end;
  1981.           expression := last_expression;
  1982.           state := 2;
  1983.            else
  1984.           !!assertion.make(tag,expression,get_comments);
  1985.           if Result = Void then
  1986.              Result := <<assertion>>;
  1987.           else
  1988.              Result.add_last(assertion);
  1989.           end;
  1990.           state := 4;
  1991.            end;
  1992.         end;
  1993.      end;
  1994.       end;
  1995.    
  1996.    a_base_type: BOOLEAN is
  1997.      --++ base_type -> "ANY" | ARRAY "[" type "]" | "BOOLEAN" | 
  1998.      --++         "CHARACTER" | "DOUBLE" | "INTEGER" | "NONE" | 
  1999.      --++         "POINTER" | "REAL" | "STRING"      
  2000.      --++
  2001.       local 
  2002.      sp: POSITION;
  2003.       do
  2004.      Result := true;
  2005.      if a_keyword(us_any) then
  2006.         !TYPE_ANY!last_base_type.make(pos(start_line,start_column));
  2007.      elseif a_keyword(us_array) then
  2008.         !!sp.make(start_line,start_column);
  2009.         if skip1('[') and then a_type and then skip1(']') then
  2010.            check
  2011.           last_type /= Void
  2012.            end;
  2013.            !TYPE_ARRAY!last_base_type.make(sp,last_type);
  2014.         else
  2015.            fcp("Bad use of predefined type ARRAY.");
  2016.         end;
  2017.      elseif a_keyword(us_native_array) then
  2018.         !!sp.make(start_line,start_column);
  2019.         if skip1('[') and then a_type and then skip1(']') then
  2020.            check
  2021.           last_type /= Void
  2022.            end;
  2023.            !TYPE_NATIVE_ARRAY!last_base_type.make(sp,last_type);
  2024.         else
  2025.            fcp("Bad use of predefined type NATIVE_ARRAY.");
  2026.         end;
  2027.      elseif a_keyword("C_ARRAY") then
  2028.         !!sp.make(start_line,start_column);
  2029.         if skip1('[') and then a_type and then skip1(']') then
  2030.            check
  2031.           last_type /= Void
  2032.            end;
  2033.            !TYPE_NATIVE_ARRAY!last_base_type.make(sp,last_type);
  2034.         else
  2035.            fcp("Bad use of predefined type C_ARRAY.");
  2036.         end;
  2037.         warning(sp,"For Java compatibility, the new name is NATIVE_ARRAY.");
  2038.      elseif a_keyword(us_boolean) then
  2039.         !TYPE_BOOLEAN!last_base_type.make(pos(start_line,start_column));
  2040.      elseif a_keyword(us_character) then
  2041.         !TYPE_CHARACTER!last_base_type.make(pos(start_line,start_column));
  2042.      elseif a_keyword(us_double) then
  2043.         !TYPE_DOUBLE!last_base_type.make(pos(start_line,start_column));
  2044.      elseif a_keyword(us_integer) then
  2045.         !TYPE_INTEGER!last_base_type.make(pos(start_line,start_column));
  2046.      elseif a_keyword(us_none) then
  2047.         !TYPE_NONE!last_base_type.make(pos(start_line,start_column));
  2048.      elseif a_keyword(us_pointer) then
  2049.         !TYPE_POINTER!last_base_type.make(pos(start_line,start_column));
  2050.      elseif a_keyword(us_real) then
  2051.         !TYPE_REAL!last_base_type.make(pos(start_line,start_column));
  2052.      elseif a_keyword(us_string) then
  2053.         !TYPE_STRING!last_base_type.make(pos(start_line,start_column));
  2054.      else
  2055.         Result := false;
  2056.      end;
  2057.       end;
  2058.    
  2059.    a_binary(sp: POSITION): BOOLEAN is
  2060.      --++ binary -> "<=" | ">=" | "//" | "\\" |
  2061.      --++           "+" | "-" | "*" | "/" | "<" | ">" | "^" | 
  2062.      --++           xor" | "implies" | "and then" | "and" | "or else" | "or" 
  2063.      --++
  2064.       do
  2065.      Result := true;
  2066.      if skip2('<','=') then
  2067.         !!last_binary.make(us_le,sp);
  2068.      elseif skip2('>','=') then
  2069.         !!last_binary.make(us_ge,sp);
  2070.      elseif skip2('/','/') then
  2071.         !!last_binary.make("//",sp);
  2072.      elseif skip2('\','\') then
  2073.         !!last_binary.make("\\",sp);
  2074.      elseif skip1('+') then
  2075.         !!last_binary.make(us_plus,sp);
  2076.      elseif skip1('-') then
  2077.         !!last_binary.make(us_minus,sp);
  2078.      elseif skip1('*') then
  2079.         !!last_binary.make(us_muls,sp);
  2080.      elseif skip1('/') then
  2081.         !!last_binary.make(us_slash,sp);
  2082.      elseif skip1('>') then
  2083.         !!last_binary.make(us_gt,sp);
  2084.      elseif skip1('<') then
  2085.         !!last_binary.make(us_lt,sp);
  2086.      elseif skip1('^') then
  2087.         !!last_binary.make("^",sp);
  2088.      elseif a_keyword(us_xor) then
  2089.         !!last_binary.make(us_xor,sp);
  2090.      elseif a_keyword(us_implies) then
  2091.         !!last_binary.make(us_implies,sp)
  2092.      elseif a_keyword(us_and) then
  2093.         if a_keyword(fz_then) then
  2094.            !!last_binary.make(us_and_then,sp);
  2095.         else
  2096.            !!last_binary.make(us_and,sp);
  2097.         end;
  2098.      elseif a_keyword(us_or) then
  2099.         if a_keyword(fz_else) then
  2100.            !!last_binary.make(us_or_else,sp);
  2101.         else
  2102.            !!last_binary.make(us_or,sp);
  2103.         end;
  2104.      else
  2105.         last_binary := Void;
  2106.         Result := false;
  2107.      end;
  2108.       end;
  2109.    
  2110.    a_boolean_constant: BOOLEAN is
  2111.      --++ boolean_constant -> "true" | "false"
  2112.      --++
  2113.       do
  2114.      if a_keyword(fz_true) then
  2115.         !E_TRUE!last_boolean_constant.make(pos(start_line,start_column));
  2116.         Result := true;
  2117.      elseif a_keyword(fz_false) then
  2118.         !E_FALSE!last_boolean_constant.make(pos(start_line,start_column));
  2119.         Result := true;
  2120.      end;
  2121.       end; 
  2122.    
  2123.    a_character_or_integer: BOOLEAN is
  2124.      --++ character_or_integer -> character_constant |
  2125.      --++                         integer_constant
  2126.      --++
  2127.       do
  2128.      if a_character_constant then
  2129.         last_character_or_integer := last_character_constant;
  2130.         Result := true;
  2131.      elseif a_integer_constant then
  2132.         last_character_or_integer := last_integer_constant;
  2133.         Result := true;
  2134.      end;
  2135.       end;
  2136.    
  2137.    a_check: BOOLEAN is
  2138.      --++ check -> "check" assertion "end"
  2139.      --++
  2140.       local
  2141.      sp: POSITION;
  2142.      hc: COMMENT;
  2143.      al: ARRAY[ASSERTION];
  2144.       do
  2145.      if a_keyword(fz_check) then
  2146.         Result := true;
  2147.         !!sp.make(start_line,start_column);
  2148.         hc := get_comments;
  2149.         al := a_assertion;
  2150.         if hc /= Void or else al /= Void then
  2151.            !E_CHECK!last_instruction.make(sp,hc,al);
  2152.         else
  2153.            wcp("Empty check instruction removed.");
  2154.         end;
  2155.         if not a_keyword(fz_end) then
  2156.            fcp("Keyword %"end%" expected at the end of check clause.");
  2157.         end;
  2158.      end;
  2159.       end;
  2160.    
  2161.    a_class_declaration is
  2162.      --++ class_declaration -> [indexing]
  2163.      --++                      ["expanded" | "deferred"]
  2164.      --++                      "class" base_class_name
  2165.      --++                      ["[" formal_generic_list "]"]
  2166.      --++                      [comment]
  2167.      --++                      ["obsolete" manifest_string]
  2168.      --++                      ["inherit" parent_list]
  2169.      --++                      {"creation" creation_clause ...} 
  2170.      --++                      {"feature" feature_clause ...} 
  2171.      --++                      ["invariant" assertion]
  2172.      --++                      "end"
  2173.      --++
  2174.       local
  2175.      sp: POSITION;
  2176.      hc: COMMENT;
  2177.      al: ARRAY[ASSERTION];
  2178.      drop_comments_save: BOOLEAN;
  2179.       do
  2180.      a_indexing; 
  2181.      if a_keyword(fz_deferred) then
  2182.         last_base_class.set_is_deferred;
  2183.      end;
  2184.      if a_keyword(fz_expanded) then      
  2185.         last_base_class.set_is_expanded;
  2186.         if a_keyword(fz_deferred) then
  2187.            last_base_class.set_is_deferred;
  2188.         end;
  2189.      end;
  2190.      last_base_class.set_heading_comment1(get_comments);
  2191.      if not a_keyword(fz_class) then
  2192.         fcp("Keyword %"class%" expected.");
  2193.      end;
  2194.      a_base_class_name1;
  2195.      a_formal_generic_list; 
  2196.      if a_keyword(fz_obsolete) then
  2197.         if a_manifest_string then
  2198.            last_base_class.set_obsolete_type_string(last_manifest_string);
  2199.         else
  2200.            fcp("Manifest string expected for %"obsolete%" clause.");
  2201.         end;
  2202.      end;
  2203.      last_base_class.set_heading_comment2(get_comments);
  2204.      if a_keyword(fz_inherit) then
  2205.         a_parent_list(pos(start_line,start_column),get_comments);
  2206.      end;
  2207.      from
  2208.      until
  2209.         not a_keyword(fz_creation)
  2210.      loop
  2211.         a_creation_clause(pos(start_line,start_column));
  2212.      end;
  2213.      from
  2214.      until
  2215.         not a_keyword(fz_feature)
  2216.      loop
  2217.         a_feature_clause; 
  2218.      end;
  2219.      drop_comments_save := drop_comments;
  2220.      drop_comments := false;
  2221.      if a_keyword(fz_invariant) then
  2222.         !!sp.make(start_line,start_column);
  2223.         hc := get_comments;
  2224.         al := a_assertion;
  2225.         last_base_class.set_invariant(sp,hc,al);
  2226.      end;
  2227.      if a_keyword(fz_end) or else last_keyword = fz_end then
  2228.         if cc = ';' then
  2229.            wcp(fz_desc);
  2230.            ok := skip1(';');
  2231.         end;
  2232.         last_base_class.set_end_comment(get_comments);
  2233.         if cc /= end_of_text then
  2234.            fcp("End of text expected.");
  2235.         end;
  2236.      else
  2237.         fcp("Keyword %"end%" expected at the end of a class.");
  2238.      end;
  2239.      drop_comments := drop_comments_save;
  2240.       end;
  2241.    
  2242.    a_class_type: BOOLEAN is
  2243.      --++ class_type -> base_type |
  2244.      --++               base_class_name ["[" {type "," ...} "]"]
  2245.      --++
  2246.       local
  2247.      state: INTEGER;
  2248.      base_class_name: CLASS_NAME;
  2249.      generic_list: ARRAY[TYPE];
  2250.      -- state 0 : `base_class_name' read.
  2251.      -- state 1 : waiting next generic argument.
  2252.      -- state 2 : waiting ',' or ']'.
  2253.      -- state 3 : end.
  2254.       do 
  2255.      if a_base_type then
  2256.         last_class_type := last_base_type;
  2257.         Result := true;
  2258.      elseif a_base_class_name then
  2259.         from  
  2260.            Result := true;
  2261.            base_class_name := last_class_name;
  2262.         until
  2263.            state > 2
  2264.         loop
  2265.            inspect 
  2266.           state
  2267.            when 0 then
  2268.           if skip1('[') then
  2269.              state := 1;
  2270.           else
  2271.              !TYPE_CLASS!last_class_type.make(base_class_name);
  2272.              state := 3;
  2273.           end;
  2274.            when 1 then
  2275.           if a_type then
  2276.              if generic_list = Void then
  2277.             generic_list := <<last_type>>;
  2278.              else
  2279.             generic_list.add_last(last_type);
  2280.              end;
  2281.              state := 2;
  2282.           elseif cc = ',' then
  2283.              wcp(em12);
  2284.              ok := skip1(',');
  2285.           elseif cc = ']' then
  2286.              state := 2;
  2287.           else
  2288.              fcp(em18);
  2289.              state := 2;
  2290.           end;
  2291.            else -- state = 2
  2292.           if skip1(',') then
  2293.              state := 1;
  2294.           elseif cc = ']' then
  2295.              if generic_list = Void then
  2296.             wcp("Empty generic list (deleted).");
  2297.             !TYPE_CLASS!last_class_type.make(base_class_name);
  2298.              else
  2299.             !TYPE_GENERIC!last_class_type.make(base_class_name,generic_list);
  2300.              end;
  2301.              ok := skip1(']');
  2302.              state := 3;
  2303.           elseif a_type then
  2304.              if generic_list = Void then
  2305.             generic_list := <<last_type>>;
  2306.              else
  2307.             generic_list.add_last(last_type);
  2308.              end;
  2309.              warning(last_type.start_position,em5);
  2310.           else
  2311.              fcp("Bad generic list.");
  2312.              state := 3;
  2313.           end;
  2314.            end;
  2315.         end;
  2316.      end; 
  2317.       end;
  2318.    
  2319.    a_clients: CLIENT_LIST is
  2320.      --++ clients -> "{" { base_class_name "," ... } "}"
  2321.      --++
  2322.       local
  2323.      sp: POSITION;
  2324.      list: CLASS_NAME_LIST;
  2325.      state: INTEGER;
  2326.      -- state 0 : waiting a base_class_name or "}" if empty list.
  2327.      -- state 1 : waiting a base_class_name after a ",".
  2328.      -- state 2 : waiting "," or "}" to end list.
  2329.      -- state 3 : error.
  2330.      -- state 4 : end.
  2331.       do
  2332.      if skip1('{') then
  2333.         from
  2334.            !!sp.make(start_line,start_column);
  2335.         until
  2336.            state > 3
  2337.         loop
  2338.            inspect 
  2339.           state
  2340.            when 0 then
  2341.           if a_base_class_name then
  2342.              !!list.make_1(last_class_name);
  2343.              state := 2;
  2344.           elseif skip1('}') then
  2345.              state := 4;
  2346.           elseif cc = ',' then
  2347.              wcp(em7);
  2348.              ok := skip1(',');
  2349.           else
  2350.              state := 3;
  2351.           end;
  2352.            when 1 then
  2353.           if a_base_class_name then 
  2354.              list.add_last(last_class_name);
  2355.              state := 2;
  2356.           elseif cc = ',' then
  2357.              wcp(em7);
  2358.              ok := skip1(',');
  2359.           elseif cc = '}' then
  2360.              wcp("Unexpected bracket.");
  2361.              ok := skip1('}');
  2362.              state := 4;
  2363.           else
  2364.              state := 3;
  2365.           end;
  2366.            when 2 then
  2367.           if skip1(',') then
  2368.              state := 1;
  2369.           elseif skip1('}') then
  2370.              state := 4;
  2371.           elseif a_base_class_name then
  2372.              warning(last_class_name.start_position,em5);
  2373.              list.add_last(last_class_name);
  2374.           else
  2375.              state := 3;
  2376.           end;          
  2377.            else -- state = 3
  2378.           fcp(em11);
  2379.           state := 4;
  2380.            end;
  2381.         end;
  2382.         !!Result.make(sp,list);
  2383.      else
  2384.         !!Result.omitted;
  2385.      end;
  2386.       ensure
  2387.      Result /= Void
  2388.       end;
  2389.    
  2390.    a_compound1: COMPOUND is
  2391.      --++ compound -> {instruction ";" ...}
  2392.      --++
  2393.       local
  2394.      hc: COMMENT;
  2395.      instruction, first_one: INSTRUCTION;
  2396.      remainder: FIXED_ARRAY[INSTRUCTION];
  2397.       do 
  2398.      from        
  2399.         hc := get_comments;
  2400.         from  
  2401.         until
  2402.            cc /= ';'
  2403.         loop
  2404.            wcp(fz_desc);
  2405.            ok := skip1(';');
  2406.         end;
  2407.      until
  2408.         not a_instruction or else nb_errors > 0
  2409.      loop
  2410.         instruction := last_instruction;
  2411.         check
  2412.            instruction /= Void;
  2413.         end;
  2414.         if cc = '(' then
  2415.            wcp(em6);
  2416.         end;
  2417.         from  
  2418.            ok := skip1(';');
  2419.         until
  2420.            cc /= ';'
  2421.         loop
  2422.            wcp(fz_desc);
  2423.            ok := skip1(';');
  2424.         end;
  2425.         if nb_errors = 0 then
  2426.            instruction := instruction.add_comment(get_comments);
  2427.            if first_one = Void then
  2428.           first_one := instruction;
  2429.            else
  2430.           if remainder = Void then
  2431.              !!remainder.with_capacity(4);
  2432.           end;
  2433.           remainder.add_last(instruction);
  2434.            end;
  2435.         end;
  2436.      end;
  2437.      if hc /= Void or else first_one /= Void then
  2438.         !!Result.make(hc,first_one,remainder);
  2439.      end;
  2440.       end;
  2441.    
  2442.    a_compound2(compound_of, terminator: STRING): COMPOUND is
  2443.      -- Like a_compound1 but stop when `terminator' is encountered. 
  2444.       local
  2445.      hc: COMMENT;
  2446.      instruction, first_one: INSTRUCTION;
  2447.      remainder: FIXED_ARRAY[INSTRUCTION];
  2448.       do 
  2449.      from        
  2450.         hc := get_comments;
  2451.         from  
  2452.         until
  2453.            cc /= ';'
  2454.         loop
  2455.            wcp(fz_desc);
  2456.            ok := skip1(';');
  2457.         end;
  2458.      until
  2459.         not a_instruction or else nb_errors > 0
  2460.      loop
  2461.         instruction := last_instruction;
  2462.         check
  2463.            instruction /= Void;
  2464.         end;
  2465.         if cc = '(' then
  2466.            wcp(em6);
  2467.         end;
  2468.         from  
  2469.            ok := skip1(';');
  2470.         until
  2471.            cc /= ';'
  2472.         loop
  2473.            wcp(fz_desc);
  2474.            ok := skip1(';');
  2475.         end;
  2476.         if nb_errors = 0 then
  2477.            instruction := instruction.add_comment(get_comments);
  2478.            if first_one = Void then
  2479.           first_one := instruction;
  2480.            else
  2481.           if remainder = Void then
  2482.              !!remainder.with_capacity(4);
  2483.           end;
  2484.           remainder.add_last(instruction);
  2485.            end;
  2486.         end;
  2487.      end;
  2488.      if not a_keyword(terminator) then
  2489.         eh.append("In compound (");
  2490.         eh.append(compound_of);
  2491.         eh.append("). Instruction or keyword %"");
  2492.         eh.append(terminator);
  2493.         fcp("%" expected.");
  2494.      end;
  2495.      if hc /= Void or else first_one /= Void then
  2496.         !!Result.make(hc,first_one,remainder);
  2497.      end;
  2498.       end;
  2499.    
  2500.    a_conditional: BOOLEAN is
  2501.      --++ conditional -> "if" then_part_list ["else" compound] "end"
  2502.      --++
  2503.       local
  2504.      ifthenelse: IFTHENELSE;
  2505.       do
  2506.      if a_keyword(fz_if) then
  2507.         Result := true;
  2508.         !!ifthenelse.make(pos(start_line,start_column)); 
  2509.         a_then_part_list(ifthenelse);
  2510.         if a_keyword(fz_else) then
  2511.            ifthenelse.set_else_compound(a_compound2("else part",fz_end));
  2512.         else
  2513.            if not a_keyword(fz_end) then
  2514.           wcp("Keyword %"end%" added.");
  2515.            end;
  2516.         end;
  2517.         last_instruction := ifthenelse;
  2518.      end;
  2519.       end;
  2520.    
  2521.    a_creation: BOOLEAN is
  2522.      --++ creation -> "!"[type]"!" writable ["." proc_name [actuals]]
  2523.      --++
  2524.       local
  2525.      sp: POSITION;
  2526.      type: TYPE;
  2527.      writable: EXPRESSION;
  2528.      proc_name: FEATURE_NAME;
  2529.      call: PROC_CALL;
  2530.      state: INTEGER;
  2531.      -- state 0 : waiting first '!'.
  2532.      -- state 1 : waiting `type' or second '!'.
  2533.      -- state 2 : waiting second '!'.
  2534.      -- state 3 : waiting `writable'.
  2535.      -- state 4 : waiting `.'.
  2536.      -- state 5 : waiting `proc_name'.
  2537.      -- state 6 : waiting `actuals'.
  2538.      -- state 7 : end.
  2539.      -- state 8 : error.
  2540.  
  2541.       do
  2542.      from  
  2543.      until
  2544.         state > 6
  2545.      loop
  2546.         inspect 
  2547.            state
  2548.         when 0 then
  2549.            if skip1('!') then
  2550.           !!sp.make(start_line,start_column);
  2551.           state := 1;
  2552.            else
  2553.           state := 7;
  2554.            end;
  2555.         when 1 then
  2556.            if a_type then
  2557.           type := last_type;
  2558.           if type.is_anchored then
  2559.              warning(type.start_position,
  2560.              "Explicit creation type mark must not be anchored.");
  2561.           end;
  2562.           state := 2;
  2563.            elseif skip1('!') then
  2564.           state := 3;
  2565.            else
  2566.           fcp("Bad creation (type or '!' expected).");
  2567.           state := 8
  2568.            end;
  2569.         when 2 then
  2570.            if skip1('!') then
  2571.           state := 3;
  2572.            else
  2573.           state := 8
  2574.           fcp("Bad creation ('!' expected).");
  2575.            end;
  2576.         when 3 then
  2577.            if a_identifier then
  2578.           if a_current then
  2579.              state := 8;
  2580.              error(last_expression.start_position,
  2581.              "Current is not a writable variable.");
  2582.           elseif a_argument then
  2583.              state := 8;
  2584.              error(last_expression.start_position,
  2585.              "A formal argument is not a writable variable.");
  2586.           elseif a_result or else a_local_variable then
  2587.              writable := last_expression;
  2588.              state := 4;
  2589.           else
  2590.              writable := tmp_name.to_simple_feature_name;
  2591.              state := 4;
  2592.           end;
  2593.            else
  2594.           state := 8;
  2595.           fcp("Bad creation (writable expected).");
  2596.            end;
  2597.         when 4 then
  2598.            if skip1unless2('.','.') then
  2599.           state := 5;
  2600.            else
  2601.           state := 7
  2602.            end;
  2603.         when 5 then
  2604.            if a_identifier then
  2605.           proc_name := tmp_name.to_simple_feature_name;
  2606.           state := 6;
  2607.            else
  2608.           state := 8;
  2609.           fcp("Bad creation (procedure name expected).");
  2610.            end;
  2611.         else -- state = 6
  2612.            if cc = '(' then
  2613.           call := to_proc_call(writable,proc_name,a_actuals);
  2614.            else
  2615.           !PROC_CALL_0!call.make(writable,proc_name);
  2616.            end;
  2617.            state := 7;
  2618.         end;
  2619.      end;
  2620.      if state = 7 and then sp /= Void then
  2621.         Result := true;
  2622.         if type = Void and then call = Void then
  2623.            !CREATION_CALL_1!last_instruction.make(sp,writable);
  2624.         elseif type /= Void and then call = Void then
  2625.            !CREATION_CALL_2!last_instruction.make(sp,type,writable);
  2626.         elseif type = Void and then call /= Void then
  2627.            !CREATION_CALL_3!last_instruction.make(sp,writable,call);
  2628.         else
  2629.            !CREATION_CALL_4!last_instruction.make(sp,type,writable,call);
  2630.         end;
  2631.      end;
  2632.       end;
  2633.    
  2634.    a_creation_clause(sp: POSITION) is
  2635.      --++ creation_clause -> [clients] [comment] feature_list
  2636.      --++
  2637.       local
  2638.      clients: CLIENT_LIST;
  2639.      comments: COMMENT;
  2640.      creation_clause: CREATION_CLAUSE;
  2641.       do
  2642.      clients := a_clients;
  2643.      comments := get_comments;
  2644.      if a_feature_name_list then
  2645.      end;
  2646.      !!creation_clause.make(sp,clients,comments,last_feature_name_list);
  2647.      last_base_class.add_creation_clause(creation_clause);
  2648.       end;
  2649.    
  2650.    a_debug: BOOLEAN is
  2651.      --++ debug -> "debug" "(" {manifest_string "," ...} ")"
  2652.      --++                  compound "end"
  2653.      --++
  2654.       local
  2655.      sp: POSITION;
  2656.      list: ARRAY[MANIFEST_STRING];
  2657.      e_debug: E_DEBUG;
  2658.       do
  2659.      if a_keyword(fz_debug) then
  2660.         !!sp.make(start_line,start_column);
  2661.         if skip1('(') then
  2662.            from        
  2663.            until
  2664.           not a_manifest_string
  2665.            loop
  2666.           if list = Void then
  2667.              list := <<last_manifest_string>>;
  2668.           else
  2669.              list.add_last(last_manifest_string);
  2670.           end;
  2671.           ok := skip1(',');
  2672.            end;
  2673.            if list = Void then
  2674.           wcp("Empty debug key list (deleted).");
  2675.            end;
  2676.            if not skip1(')') then
  2677.           fcp("%")%" expected to end debug string list.");
  2678.            end;
  2679.         end;
  2680.         Result := true;
  2681.         !!e_debug.make(sp,list,a_compound2("debug",fz_end));
  2682.         last_instruction := e_debug;
  2683.      end;
  2684.       end;
  2685.    
  2686.    a_expression: BOOLEAN is
  2687.      --++ expression -> "<<" {Expression "," ...} ">>" |
  2688.          --++               Void |
  2689.      --++               e0
  2690.      --++
  2691.       local
  2692.      sp: POSITION;
  2693.      list: ARRAY[EXPRESSION];
  2694.       do
  2695.      if skip2('<','<') then
  2696.         from    
  2697.            Result := true;
  2698.            !!sp.make(start_line,start_column);
  2699.         until
  2700.            not a_expression
  2701.         loop
  2702.            if list = Void then
  2703.           list := <<last_expression>>;
  2704.            else
  2705.           list.add_last(last_expression);
  2706.            end;
  2707.            ok := skip1(',');
  2708.         end;
  2709.         if not skip2('>','>') then
  2710.            fcp("End of manifest array expected.");
  2711.         end;
  2712.         !MANIFEST_ARRAY!last_expression.make(sp,list);
  2713.      else
  2714.         Result := a_e0;
  2715.      end;
  2716.       end;
  2717.    
  2718.    a_e0: BOOLEAN is
  2719.      --++ e0 -> e1 r1
  2720.      --++
  2721.       do
  2722.      Result := a_e1; 
  2723.      a_r1(last_expression);
  2724.       end;
  2725.    
  2726.    a_e1: BOOLEAN is
  2727.      --++ e1 -> e2 r2
  2728.      --++
  2729.       do
  2730.      Result := a_e2;
  2731.      a_r2(last_expression);
  2732.       end;
  2733.    
  2734.    a_e2: BOOLEAN is
  2735.      --++ e2 -> e3 r3
  2736.      --++
  2737.       do
  2738.      Result := a_e3; 
  2739.      a_r3(last_expression);
  2740.       end;
  2741.    
  2742.    a_e3: BOOLEAN is
  2743.      --++ e3 -> e4 r4
  2744.      --++
  2745.       do
  2746.      Result := a_e4; 
  2747.      a_r4(last_expression);
  2748.       end;
  2749.    
  2750.    a_e4: BOOLEAN is
  2751.      --++ e4 -> e5 r5
  2752.      --++
  2753.       do
  2754.      Result := a_e5; 
  2755.      a_r5(last_expression);
  2756.       end;
  2757.    
  2758.    a_e5: BOOLEAN is
  2759.      --++ e5 -> e6 r6
  2760.      --++
  2761.       do
  2762.      Result := a_e6; 
  2763.      a_r6(last_expression);
  2764.       end;
  2765.    
  2766.    a_e6: BOOLEAN is
  2767.      --++ e6 -> e7 r7
  2768.      --++
  2769.       do
  2770.      Result := a_e7; 
  2771.      a_r7(last_expression);
  2772.       end;
  2773.    
  2774.    a_e7: BOOLEAN is
  2775.      --++ e7 -> e8 r8
  2776.      --++
  2777.       do
  2778.      Result := a_e8; 
  2779.      a_r8(last_expression);
  2780.       end;
  2781.    
  2782.    a_e8: BOOLEAN is
  2783.      --++ e8 -> "not" e8 |
  2784.      --++       "+" e8 |
  2785.      --++       "-" e8 |
  2786.      --++       free_operator e8 !
  2787.      --++       e9
  2788.      --++
  2789.       local
  2790.      prefix_not: CALL_PREFIX_NOT;
  2791.      prefix_plus: CALL_PREFIX_PLUS;
  2792.      prefix_moins: CALL_PREFIX_MINUS;
  2793.      op: PREFIX_NAME;
  2794.      prefix_freeop: CALL_PREFIX_FREEOP;
  2795.      sp: POSITION;
  2796.       do
  2797.      if a_keyword(us_not) then
  2798.         !!sp.make(start_line,start_column);
  2799.         if a_e8 then
  2800.            !!prefix_not.make(sp,last_expression);
  2801.            last_expression := prefix_not;
  2802.            Result := true;
  2803.         else
  2804.            err_exp(sp,us_not);
  2805.         end;
  2806.      elseif skip1('+') then
  2807.         !!sp.make(start_line,start_column);
  2808.         if a_e8 then
  2809.            !!prefix_plus.make(sp,last_expression);
  2810.            last_expression := prefix_plus;
  2811.            Result := true;
  2812.         else
  2813.            err_exp(sp,"+ (prefix)");
  2814.         end;
  2815.      elseif skip1('-') then
  2816.         !!sp.make(start_line,start_column);
  2817.         if a_e8 then
  2818.            !!prefix_moins.make(sp,last_expression);
  2819.            last_expression := prefix_moins;
  2820.            Result := true;
  2821.         else
  2822.            err_exp(sp,"- (prefix)");
  2823.         end;
  2824.      elseif a_free_operator then
  2825.         op := tmp_name.to_prefix_name;
  2826.         if a_e8 then
  2827.            !!prefix_freeop.make(last_expression,op);
  2828.            last_expression := prefix_freeop;
  2829.            Result := true;
  2830.         else
  2831.            eh.append("Bad use of prefix operator. ");
  2832.            err_exp(op.start_position,op.to_string);
  2833.         end;
  2834.      else
  2835.         Result := a_e9;
  2836.      end;
  2837.       end;
  2838.    
  2839.    a_e9: BOOLEAN is
  2840.      --++ e9 -> e10 |
  2841.      --++       "old" e10 
  2842.      --++
  2843.       local
  2844.      e_old: E_OLD;
  2845.       do
  2846.      if a_keyword(fz_old) then
  2847.         if not in_ensure then
  2848.            error(pos(start_line,start_column),
  2849.            "Expression %"old%" can be used in ensure clause only.");
  2850.         end;
  2851.         if a_e10 then
  2852.            !!e_old.make(last_expression);
  2853.            last_expression := e_old;
  2854.            Result := true;
  2855.         else
  2856.            fcp("Expression expected after %"old%".");
  2857.         end;
  2858.      else
  2859.         Result := a_e10;
  2860.      end;
  2861.       end;
  2862.    
  2863.    a_e10: BOOLEAN is
  2864.      --++ e10 -> strip |
  2865.      --++       "(" expression ")" r10 |
  2866.      --++       manifest_constant |
  2867.      --++       precursor_call |
  2868.      --++       "Result" r10 |
  2869.      --++       "Current" r10 |
  2870.      --++       "Void" r10 |
  2871.      --++       local_variable r10 |
  2872.      --++       argument r10 |
  2873.      --++       function_call r10 |
  2874.      --++
  2875.       do
  2876.      if a_strip then
  2877.         Result := true;
  2878.      elseif skip1('(') then
  2879.         Result := true;
  2880.         if a_expression then
  2881.            if skip1(')') then
  2882.           a_r10(false,last_expression,Void,Void);
  2883.            else
  2884.           fcp("')' expected in expression.")
  2885.            end;
  2886.         else
  2887.            fcp("Expression expected.")
  2888.         end;
  2889.      elseif a_manifest_constant then
  2890.         last_expression := last_manifest_constant;
  2891.         Result := true;
  2892.         if skip1unless2('.','.') then
  2893.            wcp("Added brackets for manifest constant before dot.");
  2894.            a_after_a_dot(false,last_expression);
  2895.         end;
  2896.      elseif a_precursor(false) then
  2897.             Result := true;
  2898.      elseif a_identifier then
  2899.         Result := true;
  2900.         if a_result or else a_current or else a_void or else
  2901.            a_local_variable or else a_argument then
  2902.            a_r10(false,last_expression,Void,Void);
  2903.         else
  2904.            a_function_call;
  2905.         end; 
  2906.      end;
  2907.       end;
  2908.          
  2909.    a_external: ROUTINE is
  2910.      --++ external -> "XXX" external_name |
  2911.      --++             "YYY" external_name |
  2912.      --++             "..." external_name
  2913.      --++
  2914.       local
  2915.      l: NATIVE;
  2916.       do
  2917.      if cc /= '%"' then
  2918.         wcp(em19);
  2919.      else
  2920.         ok := skip1('%"');
  2921.      end;
  2922.      if a_keyword(fz_se) then
  2923.         !NATIVE_SMALL_EIFFEL!l;
  2924.      elseif a_keyword(fz_c_withcurrent) then
  2925.         !NATIVE_WITH_CURRENT!l;
  2926.      elseif a_keyword(fz_c_inlinewithcurrent) then
  2927.         !NATIVE_INLINE_WITH_CURRENT!l;
  2928.      elseif a_keyword(fz_c_withoutcurrent) then
  2929.         !NATIVE_WITHOUT_CURRENT!l;
  2930.      elseif a_keyword(fz_c_inlinewithoutcurrent) then
  2931.         !NATIVE_INLINE_WITHOUT_CURRENT!l;
  2932.      elseif a_keyword("CSE") then
  2933.         !NATIVE_SMALL_EIFFEL!l;
  2934.         wcpefnc("CSE",fz_se);
  2935.      elseif a_keyword("CWC") then
  2936.         !NATIVE_WITH_CURRENT!l;
  2937.         wcpefnc("CWC",fz_c_withcurrent);
  2938.      elseif a_keyword("ICWC") then
  2939.         !NATIVE_INLINE_WITH_CURRENT!l;
  2940.         wcpefnc("ICWC",fz_c_inlinewithcurrent);
  2941.      elseif a_keyword("C") then
  2942.         !NATIVE_WITHOUT_CURRENT!l;
  2943.      elseif a_keyword("IC") then
  2944.         !NATIVE_INLINE_WITHOUT_CURRENT!l;
  2945.         wcpefnc("IC",fz_c_inlinewithoutcurrent);
  2946.      elseif a_keyword(fz_jvm_invokestatic) then
  2947.         !NATIVE_JVM_INVOKESTATIC!l;
  2948.      elseif a_keyword(fz_jvm_invokevirtual) then
  2949.         !NATIVE_JVM_INVOKEVIRTUAL!l;
  2950.      else
  2951.         fcp("Unkown external specification. Currently supported %
  2952.             % keywords are : %"C_WithCurrent%", %"C_InlineWithCurrent%", %
  2953.         %%"C_WithoutCurrent%", %"C_InlineWithoutCurrent%" and %
  2954.             %%"SmallEiffel%".");
  2955.      end;
  2956.      if cc /= '%"' then
  2957.         wcp(em19);
  2958.      else
  2959.         ok := skip1('%"');
  2960.      end;
  2961.      Result := tmp_feature.to_external_routine(l,a_alias);
  2962.       end;
  2963.          
  2964.    a_alias: STRING is
  2965.      --++ external_name -> ["alias" manifest_string]
  2966.      --++
  2967.       do
  2968.      if a_keyword(fz_alias) then
  2969.         if a_manifest_string then
  2970.            Result := last_manifest_string.to_string;
  2971.         else
  2972.            fcp("Alias name of external expected.");
  2973.         end;
  2974.      end;
  2975.       end;
  2976.    
  2977.    a_feature_name_list: BOOLEAN is
  2978.      --++ feature_name_list -> {feature_name "," ...}
  2979.      --++
  2980.      --
  2981.      -- Gives true when list is not empty.
  2982.       local
  2983.      state: INTEGER;
  2984.      -- state 0 : nothing read.
  2985.      -- state 1 : feature name read.
  2986.      -- state 2 : separator read.
  2987.      -- state 3 : end.
  2988.       do
  2989.      from        
  2990.         last_feature_name_list := Void;
  2991.      until
  2992.         state >= 3
  2993.      loop
  2994.         inspect
  2995.            state
  2996.         when 0 then
  2997.            if a_feature_name then
  2998.           !!last_feature_name_list.make_1(last_feature_name);
  2999.           Result := true;
  3000.           state := 1;
  3001.            elseif cc = ',' then
  3002.           wcp(em7);
  3003.           ok := skip1(',');
  3004.            else
  3005.           state := 3
  3006.            end;
  3007.         when 1 then
  3008.            if cc = ',' then
  3009.           ok := skip1(',');
  3010.           state := 2;
  3011.            elseif a_feature_name then
  3012.           warning(last_feature_name.start_position,em5);
  3013.           last_feature_name_list.add_last(last_feature_name);
  3014.            else
  3015.           state := 3;
  3016.            end;
  3017.         when 2 then
  3018.            if a_feature_name then
  3019.           last_feature_name_list.add_last(last_feature_name);
  3020.           state := 1;
  3021.            elseif cc = ',' then
  3022.           wcp(em12);
  3023.           ok := skip1(',');
  3024.            else
  3025.           ecp(em2);
  3026.           state := 3;
  3027.            end;
  3028.         end;
  3029.      end;
  3030.       end;
  3031.    
  3032.    a_feature_name: BOOLEAN is
  3033.      --++ feature_name -> prefix |
  3034.      --++                 infix |
  3035.      --++                 simple_feature_name
  3036.      --++
  3037.       do
  3038.      if a_prefix then
  3039.         last_feature_name := last_prefix;
  3040.         Result := true;
  3041.      elseif a_infix then
  3042.         last_feature_name := last_infix;
  3043.         Result := true;
  3044.      elseif a_identifier then
  3045.         last_feature_name := tmp_name.to_simple_feature_name;
  3046.         Result := true;
  3047.      end;
  3048.       end;
  3049.  
  3050.    a_feature_clause is
  3051.      --++ feature_clause -> [clients] [comment] feature_declaration_list
  3052.      --++
  3053.       local
  3054.      feature_clause: FEATURE_CLAUSE;
  3055.      clients: CLIENT_LIST;
  3056.      comment: COMMENT;
  3057.       do   
  3058.      from
  3059.         clients := a_clients;
  3060.         comment := get_comments;
  3061.         faof.clear;
  3062.      until
  3063.         not a_feature_declaration
  3064.      loop
  3065.         ok := skip1(';');
  3066.         if last_feature_declaration /= Void then
  3067.            faof.add_last(last_feature_declaration);
  3068.            last_feature_declaration.set_header_comment(get_comments);
  3069.         end;
  3070.      end;
  3071.      if not faof.empty then
  3072.         !!feature_clause.make(clients,comment,faof.twin);
  3073.         last_base_class.add_feature_clause(feature_clause);
  3074.      elseif comment /= Void then
  3075.         !!feature_clause.make(clients,comment,Void);
  3076.         last_base_class.add_feature_clause(feature_clause);
  3077.      end;
  3078.      last_keyword := Void;
  3079.       end;
  3080.    
  3081.    a_feature_declaration: BOOLEAN is
  3082.      --++ feature_declaration -> {["frozen"] feature_name "," ...}+
  3083.      --++                        formal_arg_list
  3084.      --++                        [":" type] 
  3085.      --++                        ["is" "unique" | 
  3086.      --++                         "is" manifest_constant | 
  3087.      --++                         "is" routine]
  3088.      --++
  3089.       do   
  3090.      from
  3091.         tmp_feature.initialize;
  3092.         if a_keyword(fz_frozen) then
  3093.            if a_feature_name then
  3094.           Result := true;
  3095.           to_frozen_feature_name;
  3096.           tmp_feature.add_synonym(last_feature_name);
  3097.            else
  3098.           fcp(em2);
  3099.            end;
  3100.         elseif a_feature_name then
  3101.            Result := true;
  3102.            tmp_feature.add_synonym(last_feature_name);
  3103.         end;
  3104.      until
  3105.         not skip1(',')
  3106.      loop
  3107.         if a_keyword(fz_frozen) then
  3108.            if a_feature_name then
  3109.           to_frozen_feature_name;
  3110.           tmp_feature.add_synonym(last_feature_name);
  3111.            else
  3112.           fcp("Frozen feature name synonym expected.");
  3113.            end;
  3114.         elseif a_feature_name then
  3115.            tmp_feature.add_synonym(last_feature_name);
  3116.         else
  3117.            ecp("Synonym feature name expected.");
  3118.         end;
  3119.      end;
  3120.      if Result then
  3121.         a_formal_arg_list;
  3122.         if skip1(':') then
  3123.            if a_type then
  3124.           inside_function := true;
  3125.           tmp_feature.set_type(last_type);
  3126.            else
  3127.           fcp(em18);
  3128.            end;
  3129.         else
  3130.            inside_function := false;
  3131.         end;
  3132.         if a_keyword(fz_is) then
  3133.            if a_keyword(fz_unique) then
  3134.           last_feature_declaration := tmp_feature.to_cst_att_unique;
  3135.            elseif a_boolean_constant then
  3136.           last_feature_declaration := 
  3137.              tmp_feature.to_cst_att_boolean(last_boolean_constant);
  3138.            elseif a_character_constant then
  3139.           last_feature_declaration := 
  3140.              tmp_feature.to_cst_att_character(last_character_constant);
  3141.            elseif a_manifest_string then
  3142.           last_feature_declaration := 
  3143.              tmp_feature.to_cst_att_string(last_manifest_string);
  3144.            elseif a_bit_constant then
  3145.           last_feature_declaration := 
  3146.              tmp_feature.to_cst_att_bit(last_bit_constant);
  3147.            elseif a_real_constant then
  3148.           last_feature_declaration := 
  3149.              tmp_feature.to_cst_att_real(last_real_constant);
  3150.            elseif a_integer_constant then
  3151.           last_feature_declaration := 
  3152.              tmp_feature.to_cst_att_integer(last_integer_constant);
  3153.            else 
  3154.           last_feature_declaration := a_routine;
  3155.            end;
  3156.         else
  3157.            last_feature_declaration := tmp_feature.to_writable_attribute;
  3158.         end;
  3159.         inside_function := false;
  3160.         inside_once_function := false;
  3161.         arguments := Void;
  3162.      end;
  3163.       end;
  3164.    
  3165.    a_formal_generic_list is
  3166.      --++ formal_generic_list -> ["[" {formal_generic "," ...} "]"]
  3167.      --++ formal_generic -> base_class_name ["->" class_type]
  3168.      --++
  3169.       local
  3170.      sp: POSITION;
  3171.      name: CLASS_NAME;
  3172.      constraint: TYPE;
  3173.      fga: FORMAL_GENERIC_ARG;
  3174.      list: ARRAY[FORMAL_GENERIC_ARG];
  3175.      state: INTEGER;
  3176.      -- state 0 : waiting for "[".
  3177.      -- state 1 : waiting for a base class `name'.
  3178.      -- state 2 : waiting for "->" or "," or "]".
  3179.      -- state 3 : waiting for "," or "]".
  3180.      -- state 4 : waiting for a `constraint' type.
  3181.      -- state 5 : end. 
  3182.      -- state 6 : error.
  3183.       do   
  3184.      from  
  3185.         formal_generic_list := Void;
  3186.      until
  3187.         state > 4 
  3188.      loop
  3189.         inspect 
  3190.            state
  3191.         when 0 then
  3192.            if skip1('%(') then
  3193.           !!sp.make(start_line,start_column);
  3194.           state := 1;
  3195.            else
  3196.           state := 5;
  3197.            end;
  3198.         when 1 then
  3199.            if a_base_class_name then
  3200.           name := last_class_name;
  3201.           state := 2;
  3202.            else
  3203.           state := 6;
  3204.            end;
  3205.         when 2 then
  3206.            if skip2('-','>') then
  3207.           state := 4;
  3208.            elseif cc = ',' or else cc = ']' then
  3209.           !!fga.make(name,constraint);
  3210.           name := Void;
  3211.           constraint := Void;
  3212.           if list = Void then
  3213.              list := <<fga>>;
  3214.           else
  3215.              list.add_last(fga);
  3216.           end;
  3217.           fga := Void;
  3218.           if skip1(',') then
  3219.              state := 1;
  3220.           else
  3221.              ok := skip1('%)');
  3222.              state := 5;
  3223.           end;
  3224.            else
  3225.           state := 6;
  3226.            end;
  3227.         when 3 then
  3228.            if cc = ',' or else cc = ']' then
  3229.           !!fga.make(name,constraint);
  3230.           name := Void;
  3231.           constraint := Void;
  3232.           if list = Void then
  3233.              list := <<fga>>;
  3234.           else
  3235.              list.add_last(fga);
  3236.           end;
  3237.           fga := Void;
  3238.           if skip1(',') then
  3239.              state := 1;
  3240.           else
  3241.              ok := skip1('%)');
  3242.              state := 5;
  3243.           end;
  3244.            else
  3245.           state := 6;
  3246.            end;
  3247.         else -- state = 4
  3248.            if a_class_type then
  3249.           constraint := last_class_type;
  3250.           state := 3;
  3251.            else
  3252.           fcp("Constraint Class name expected.");
  3253.           state := 6;
  3254.            end;
  3255.         end;
  3256.      end;
  3257.      if state = 6 then
  3258.         check
  3259.            nb_errors > 0;
  3260.         end;
  3261.      elseif sp /= Void and then list = Void then
  3262.         warning(sp,"Empty formal generic list (deleted).");
  3263.      elseif sp /= Void then
  3264.         check 
  3265.            not list.empty;
  3266.         end;
  3267.         !!formal_generic_list.make(sp,list);
  3268.         last_base_class.set_formal_generic_list(formal_generic_list);
  3269.      end;
  3270.       end;
  3271.    
  3272.    a_function_call is
  3273.      --++ function_call -> [actuals] r10 |
  3274.      --++                   ^
  3275.      --++
  3276.       local
  3277.         sfn: SIMPLE_FEATURE_NAME;
  3278.      implicit_current: IMPLICIT_CURRENT;
  3279.       do        
  3280.      sfn := tmp_name.to_simple_feature_name;
  3281.      !!implicit_current.make(sfn.start_position);
  3282.      a_r10(false,implicit_current,sfn,a_actuals);
  3283.       end;
  3284.    
  3285.    a_index_clause: BOOLEAN is
  3286.      --++ index_clause -> [identifier ":"] {index_value "," ...}+
  3287.      --++
  3288.       local
  3289.      index_clause: INDEX_CLAUSE;
  3290.       do
  3291.      if a_identifier then
  3292.         Result := true;
  3293.         if skip1(':') then
  3294.            !!index_clause.with_tag(tmp_name.to_string);
  3295.            if a_index_value then
  3296.           index_clause.add_last(last_index_value);
  3297.            else
  3298.           fcp(em3);
  3299.            end;
  3300.         else
  3301.            !!index_clause.without_tag(tmp_name.to_simple_feature_name);
  3302.         end;
  3303.      elseif a_manifest_constant then
  3304.         Result := true;
  3305.         !!index_clause.without_tag(last_manifest_constant);
  3306.      end;
  3307.      if Result then
  3308.         from  
  3309.         until
  3310.            not skip1(',')
  3311.         loop
  3312.            if a_index_value then
  3313.           index_clause.add_last(last_index_value);
  3314.            else
  3315.           fcp(em3);
  3316.            end;
  3317.         end;
  3318.         last_base_class.add_index_clause(index_clause);
  3319.      end;
  3320.       end;
  3321.       
  3322.    a_index_value: BOOLEAN is
  3323.      --++ index_value -> identifier | manifest_constant
  3324.      --++
  3325.       do
  3326.      if a_identifier then
  3327.         last_index_value := tmp_name.to_simple_feature_name;
  3328.         Result := true;
  3329.      elseif a_manifest_constant then
  3330.         last_index_value := last_manifest_constant;
  3331.         Result := true;
  3332.      end;
  3333.       end;
  3334.    
  3335.    a_indexing is
  3336.      --++ indexing -> "indexing" {index_clause ";" ...}
  3337.      --++
  3338.       do
  3339.      if a_keyword(fz_indexing) then
  3340.         from        
  3341.         until
  3342.            not a_index_clause
  3343.         loop
  3344.            ok := skip1(';');
  3345.         end;
  3346.      end;
  3347.       end;
  3348.    
  3349.    a_infix: BOOLEAN is
  3350.      --++ infix -> "infix" "%"" binary "%""
  3351.      --++          "infix" "%"" free_operator "%""
  3352.      --++
  3353.       local
  3354.      sp: POSITION;
  3355.       do
  3356.      if a_keyword(fz_infix) then
  3357.         Result := true;
  3358.         !!sp.make(start_line,start_column);
  3359.         if cc = '%"' then
  3360.            next_char;
  3361.         else
  3362.            wcp("Character '%%%"' inserted after %"infix%".");
  3363.         end;
  3364.         if a_binary(sp) then 
  3365.            last_infix := last_binary;
  3366.         elseif a_free_operator then
  3367.            last_infix := tmp_name.to_infix_name(sp);
  3368.         else
  3369.            fcp("Infix operator name expected.");
  3370.         end;
  3371.         if not skip1('%"') then
  3372.            wcp("Character '%%%"' inserted.");
  3373.         end;
  3374.      end;
  3375.       end;
  3376.       
  3377.    a_inspect: BOOLEAN is
  3378.      --++ inspect -> "inspect" expression 
  3379.      --++            {when_part ...}
  3380.      --++            ["else" compound]
  3381.      --++            "end"
  3382.      --++
  3383.       local
  3384.      sp, spec: POSITION;
  3385.      i: E_INSPECT;
  3386.      ec: COMPOUND;
  3387.       do
  3388.      if a_keyword(fz_inspect) then
  3389.         Result := true;
  3390.         !!sp.make(start_line,start_column);
  3391.         if a_expression then
  3392.            last_expression := last_expression.add_comment(get_comments);
  3393.         else
  3394.            fcp("Expression expected (%"inspect ... %").");
  3395.         end;
  3396.         from  
  3397.            !!i.make(sp,last_expression);
  3398.         until
  3399.            not a_when_part(i)
  3400.         loop
  3401.         end;
  3402.         if a_keyword(fz_else) then
  3403.            !!spec.make(start_line,start_column);
  3404.            ec := a_compound2("else of inspect",fz_end);
  3405.            i.set_else_compound(spec,ec);
  3406.         elseif not a_keyword(fz_end) then
  3407.            wcp("Added %"end%" for inspect instruction.");
  3408.         end;     
  3409.         last_instruction := i;
  3410.      end;
  3411.       end;
  3412.    
  3413.    a_instruction: BOOLEAN is
  3414.      --++ instruction -> check | debug | conditionnal | retry |
  3415.      --++                inspect | loop | creation | assignment_or_call   
  3416.      --++ 
  3417.       do   
  3418.      Result := a_check or else a_debug or else a_conditional or else
  3419.                    a_retry or else a_inspect or else a_loop or else 
  3420.            a_creation or else a_assignment_or_call;
  3421.       end;
  3422.    
  3423.    a_integer_constant: BOOLEAN is
  3424.      --++ integer_constant -> ["+" | "-"] integer
  3425.      --++
  3426.       local
  3427.      l, c: INTEGER;
  3428.       do
  3429.      if skip1('+') then
  3430.         l := start_line;
  3431.         c := start_column;
  3432.         if a_integer then
  3433.            last_integer_constant.start_position.set_line_column(l,c);
  3434.            Result := true;
  3435.         else
  3436.            fcp(fz_iinaiv);
  3437.         end;
  3438.      elseif skip1('-') then
  3439.         l := start_line;
  3440.         c := start_column;
  3441.         if a_integer then
  3442.            last_integer_constant.start_position.set_line_column(l,c);
  3443.            last_integer_constant.unary_minus;
  3444.            Result := true;
  3445.         else
  3446.            fcp(fz_iinaiv);
  3447.         end;
  3448.      else
  3449.         Result := a_integer;
  3450.      end;
  3451.       end; 
  3452.    
  3453.    a_loop: BOOLEAN is
  3454.      --++ loop -> "from" compound 
  3455.      --++         ["invariant"] assertion
  3456.      --++         ["variant" [identifier ":"] expression]
  3457.      --++         "until" expression
  3458.      --++         "loop" compound 
  3459.      --++         "end"
  3460.      --++
  3461.       local
  3462.      l1, c1, l2, c2: INTEGER;
  3463.      e_loop: E_LOOP;
  3464.      i: COMPOUND;
  3465.      ic: LOOP_INVARIANT; 
  3466.      vc: LOOP_VARIANT;
  3467.      ue: EXPRESSION;
  3468.      lb: COMPOUND;
  3469.      hc: COMMENT;
  3470.      al: ARRAY[ASSERTION];
  3471.       do
  3472.      if a_keyword(fz_from) then
  3473.         Result := true;
  3474.         l1 := start_line;
  3475.         c1 := start_column;
  3476.         i := a_compound1;
  3477.         if a_keyword(fz_invariant) then
  3478.            l2 := start_line;
  3479.            c2 := start_column;
  3480.            hc := get_comments;
  3481.            al := a_assertion;
  3482.            if hc /= Void or else al /= Void then
  3483.           !!ic.make(pos(l2,c2),hc,al);
  3484.            end;
  3485.         end;
  3486.         if a_keyword(fz_variant) then
  3487.            if a_tag_mark and then a_expression then
  3488.           !LOOP_VARIANT_2!vc.make(last_tag_mark,last_expression,
  3489.                                   get_comments);
  3490.            elseif a_expression then 
  3491.           !LOOP_VARIANT_1!vc.make(last_expression,get_comments);
  3492.            else
  3493.           wcp("Variant (INTEGER) Expression Expected.");
  3494.            end;
  3495.         end;
  3496.         if a_keyword(fz_until) then
  3497.            if a_expression then
  3498.           ue := last_expression.add_comment(get_comments);
  3499.            else
  3500.           fcp("Boolean expression expected (until).");
  3501.           ue := last_expression;
  3502.            end;
  3503.         else
  3504.            fcp("Keyword %"until%" expected (in a loop).");
  3505.            ue := last_expression;
  3506.         end;
  3507.         if cc = ';' then
  3508.            wcp(fz_desc);
  3509.            ok := skip1(';');
  3510.         end;
  3511.         if not a_keyword(fz_loop) then
  3512.            wcp("Keyword %"loop%" expected (in a loop).");
  3513.         end;
  3514.         lb := a_compound2("loop body",fz_end);
  3515.         !!e_loop.make(pos(l1,c1),i,ic,vc,ue,lb);
  3516.         last_instruction := e_loop;
  3517.      end;
  3518.       end; 
  3519.    
  3520.    a_manifest_constant: BOOLEAN is
  3521.      --++ manifest_constant -> boolean_constant | character_constant |
  3522.      --++                      real_constant | integer_constant |
  3523.      --++                      manifest_string | bit_constant
  3524.      --++
  3525.       do
  3526.      if a_boolean_constant then
  3527.         last_manifest_constant := last_boolean_constant;
  3528.         Result := true;
  3529.      elseif a_character_constant then
  3530.         last_manifest_constant := last_character_constant;
  3531.         Result := true;
  3532.      elseif a_manifest_string then
  3533.         last_manifest_constant := last_manifest_string;
  3534.         Result := true;
  3535.      elseif a_bit_constant then
  3536.         last_manifest_constant := last_bit_constant;
  3537.         Result := true;
  3538.      elseif a_real_constant then
  3539.         last_manifest_constant := last_real_constant;
  3540.         Result := true;
  3541.      elseif a_integer_constant then
  3542.         last_manifest_constant := last_integer_constant;
  3543.         Result := true;
  3544.      end;
  3545.       end;
  3546.    
  3547.    a_new_export_list is
  3548.      --++ new_export_list -> ["export" {new_export_item ";" ...}]
  3549.      --++ new_export_item -> clients "all" |
  3550.      --++                    clients feature_list
  3551.      --++
  3552.       local
  3553.      export_list: EXPORT_LIST;
  3554.      sp: POSITION;
  3555.      clients: CLIENT_LIST;
  3556.      items: ARRAY[EXPORT_ITEM];
  3557.      new_export_item: EXPORT_ITEM;
  3558.      state: INTEGER;
  3559.      -- state 0 : waiting for a `clients'.
  3560.      -- state 1 : `clients' read.
  3561.      -- state 2 : waiting ";" before next one.
  3562.      -- state 3 : error.
  3563.      -- state 4 : end.
  3564.      -- 
  3565.       do
  3566.      if a_keyword(fz_export) then
  3567.         from
  3568.            !!sp.make(start_line,start_column);
  3569.         until
  3570.            state > 3
  3571.         loop
  3572.            inspect 
  3573.           state
  3574.            when 0 then
  3575.           if cc = '{' then
  3576.              clients := a_clients;
  3577.              state := 1;
  3578.           elseif cc = ';' then
  3579.              wcp(fz_desc);
  3580.              ok := skip1(';');
  3581.           else
  3582.              if items /= Void then
  3583.             !!export_list.make(sp,items);
  3584.             last_parent.set_export(export_list);
  3585.              end;
  3586.              state := 4;
  3587.           end;
  3588.            when 1 then
  3589.           if a_keyword(fz_all) then
  3590.              !!new_export_item.make_all(clients);
  3591.              if items = Void then
  3592.             items := <<new_export_item>>;
  3593.              else
  3594.             items.add_last(new_export_item);
  3595.              end;
  3596.              state := 2;
  3597.           else
  3598.              if a_feature_name_list then
  3599.             !!new_export_item.make(clients,last_feature_name_list);
  3600.             if items = Void then
  3601.                items := <<new_export_item>>;
  3602.             else
  3603.                items.add_last(new_export_item);
  3604.             end;
  3605.             state := 2;
  3606.              else
  3607.             state := 3;
  3608.              end;
  3609.           end;
  3610.            when 2 then
  3611.           if skip1(';') then
  3612.              state := 0;
  3613.           elseif cc = '{' then
  3614.              wcp(em6);
  3615.              state := 0;
  3616.           else
  3617.              if items /= Void then
  3618.             !!export_list.make(sp,items);
  3619.             last_parent.set_export(export_list);
  3620.              end;
  3621.              state := 4;
  3622.           end;
  3623.            else -- state = 3
  3624.           fcp(em11);
  3625.           state := 4;
  3626.            end;
  3627.         end;
  3628.      end;
  3629.       end;
  3630.    
  3631.    a_parent_list(sp: POSITION; hc: COMMENT) is
  3632.      --++ parent_list -> {parent ";" ...}
  3633.      --++
  3634.       local
  3635.      list: ARRAY[PARENT];
  3636.       do 
  3637.      from        
  3638.      until
  3639.         not a_parent
  3640.      loop
  3641.         if list = Void then
  3642.            list := <<last_parent>>;
  3643.         else
  3644.            list.add_last(last_parent);
  3645.         end;
  3646.         ok := skip1(';');
  3647.         last_parent.set_comment(get_comments);
  3648.      end;
  3649.      if hc /= Void or else list /= Void then
  3650.         if list = Void then
  3651.            if last_base_class.heading_comment2 = Void then
  3652.           last_base_class.set_heading_comment2(hc);
  3653.            else
  3654.           last_base_class.heading_comment2.append(hc);
  3655.            end;
  3656.         else
  3657.            last_base_class.set_parent_list(sp,hc,list);
  3658.         end;
  3659.      end;
  3660.       end;
  3661.    
  3662.    a_parent: BOOLEAN is
  3663.      --++ parent -> class_type
  3664.      --++           ["rename" rename_list]
  3665.      --++           new_export_list
  3666.      --++           ["undefine" feature_name_list]
  3667.      --++           ["redefine" feature_name_list]
  3668.      --++           ["select" feature_name_list]
  3669.      --++           ["end"]
  3670.      --++
  3671.       do
  3672.      if a_class_type then
  3673.         Result := true;
  3674.         !!last_parent.make(last_class_type);
  3675.         if a_keyword(fz_rename) then
  3676.            a_rename_list;
  3677.            if cc = ';' then
  3678.           wcp("Unexpected %";%" to end rename list.");
  3679.           ok := skip1(';');
  3680.            end;
  3681.         end;
  3682.         a_new_export_list;
  3683.         if a_keyword(fz_undefine) then
  3684.            if a_feature_name_list then
  3685.           last_parent.set_undefine(last_feature_name_list)
  3686.            end;
  3687.         end;
  3688.         if a_keyword(fz_redefine) then
  3689.            if a_feature_name_list then
  3690.           last_parent.set_redefine(last_feature_name_list)
  3691.            end;
  3692.         end;
  3693.         if a_keyword(fz_select) then
  3694.            if a_feature_name_list then
  3695.           last_parent.set_select(last_feature_name_list);
  3696.            end;
  3697.         end;
  3698.         if a_keyword(fz_rename) or else 
  3699.            a_keyword(fz_export) or else 
  3700.            a_keyword(fz_undefine) or else 
  3701.            a_keyword(fz_redefine) or else  
  3702.            a_keyword(fz_select) then
  3703.            eh.add_position(pos(start_line,start_column));
  3704.            fatal_error("Inheritance option not at a good place. %
  3705.                        %The good order is: %"rename... export... %
  3706.                %undefine... redefine... select...%".",);
  3707.         end;
  3708.         ok := a_keyword(fz_end);
  3709.      end;
  3710.       end;
  3711.    
  3712.    a_prefix: BOOLEAN is
  3713.      --++ prefix -> "prefix" "%"" unary "%""
  3714.      --++           "prefix" "%"" free_operator "%""
  3715.      --++
  3716.       do
  3717.      if a_keyword(fz_prefix) then
  3718.         Result := true;
  3719.         if cc = '%"' then
  3720.            next_char;
  3721.         else
  3722.            wcp("Character '%%%"' inserted after %"prefix%".");
  3723.         end;
  3724.         if a_unary then
  3725.         elseif a_free_operator then
  3726.            last_prefix := tmp_name.to_prefix_name;
  3727.         else
  3728.            fcp("Prefix operator name expected.");
  3729.         end;
  3730.         if not skip1('%"') then
  3731.            wcp("Character '%%%"' inserted.");
  3732.         end;
  3733.      end;
  3734.       end;
  3735.  
  3736.    a_precursor(do_instruction: BOOLEAN): BOOLEAN is
  3737.          --++ precursor -> ["{" class_name "}"] "Precursor" [actuals] |
  3738.      --++              ^
  3739.          --++
  3740.       local
  3741.      sp: POSITION;
  3742.      parent: CLASS_NAME;
  3743.      args: EFFECTIVE_ARG_LIST;
  3744.       do
  3745.      if skip1('{') then
  3746.             Result := true;
  3747.         !!sp.make(start_line,start_column);
  3748.         if skip1('{') then
  3749.            warning(pos(start_line,start_column),
  3750.                "One single opening '{' is correct too here.");
  3751.         end;
  3752.         if a_base_class_name then
  3753.            parent := last_class_name;
  3754.         end;
  3755.         if not skip1('}')  then
  3756.            fcp("Closing '}' expected to end Precursor's parent qualification.");
  3757.         end;
  3758.         if skip1('}') then
  3759.            warning(pos(start_line,start_column),
  3760.                "One single closing '}' is correct too here.");
  3761.         end;
  3762.      end;
  3763.      if a_keyword(us_precursor) then
  3764.             Result := true;
  3765.         if sp = Void then
  3766.            !!sp.make(start_line,start_column);
  3767.         end;
  3768.         args := a_actuals;
  3769.      elseif sp /= Void then
  3770.         fcp("Precursor keyword expected here.");
  3771.      end;
  3772.      if Result then
  3773.         if skip1unless2('.','.') then
  3774.            !E_PRECURSOR_FUNCTION!last_expression.make(sp,parent,args);
  3775.            a_after_a_dot(do_instruction,last_expression);
  3776.         elseif do_instruction then
  3777.            !E_PRECURSOR_PROCEDURE!last_instruction.make(sp,parent,args);
  3778.         else
  3779.            !E_PRECURSOR_FUNCTION!last_expression.make(sp,parent,args);
  3780.         end;
  3781.      end;
  3782.       end;
  3783.       
  3784.    a_procedure_call is
  3785.      --++ procedure_call -> [actuals] r10 |
  3786.      --++                   ^
  3787.      --++
  3788.       local
  3789.         sfn: SIMPLE_FEATURE_NAME;
  3790.      implicit_current: IMPLICIT_CURRENT;
  3791.       do        
  3792.      sfn := tmp_name.to_simple_feature_name;
  3793.      !!implicit_current.make(sfn.start_position);
  3794.      a_r10(true,implicit_current,sfn,a_actuals);
  3795.       end;
  3796.    
  3797.    a_real_constant: BOOLEAN is
  3798.      --++ real_constant -> ["+" | "-"] real
  3799.      --++
  3800.       local
  3801.      l, c: INTEGER;
  3802.       do
  3803.      l := line;
  3804.      c := column;
  3805.      if skip1('+') then
  3806.         if a_real then
  3807.            last_real_constant.start_position.set_line_column(l,c);
  3808.            Result := true;
  3809.         else
  3810.            go_back_at(l,c);
  3811.         end;
  3812.      elseif skip1('-') then
  3813.         if a_real then
  3814.            last_real_constant.start_position.set_line_column(l,c);
  3815.            last_real_constant.unary_minus;
  3816.            Result := true;
  3817.         else
  3818.            go_back_at(l,c);
  3819.         end;
  3820.      elseif a_real then
  3821.         Result := true;
  3822.      end;
  3823.       end;
  3824.    
  3825.    a_rename_list is
  3826.      --++ rename_list -> {rename_pair "," ...}
  3827.      --++
  3828.       do
  3829.      from
  3830.      until
  3831.         not a_rename_pair
  3832.      loop
  3833.         ok := skip1(',');
  3834.      end;
  3835.       end;
  3836.    
  3837.    a_rename_pair: BOOLEAN is
  3838.      --++ rename_pair -> identifier "as" identifier
  3839.      --++
  3840.       local
  3841.      name1: FEATURE_NAME;
  3842.      rename_pair: RENAME_PAIR;
  3843.       do
  3844.      if a_feature_name then
  3845.         name1 := last_feature_name;
  3846.         if a_keyword(fz_as) then
  3847.            if a_feature_name then
  3848.           Result := true;
  3849.           !!rename_pair.make(name1,last_feature_name);
  3850.           last_parent.add_rename(rename_pair);
  3851.            else
  3852.           fcp("Second identifier of a %"rename%" pair expected.");
  3853.            end;
  3854.         else
  3855.            go_back(name1.start_position);
  3856.         end;           
  3857.      end;
  3858.       end;
  3859.    
  3860.    a_routine: ROUTINE is
  3861.      --++ routine -> ["obsolete" manifest_string]
  3862.      --++            ["require" ["else"] assertion]
  3863.      --++            ["local" entity_declaration_list]
  3864.      --++            routine_body
  3865.      --++            ["ensure" ["then"] assertion]
  3866.      --++            ["rescue" compound]
  3867.      --++            "end"
  3868.      --++
  3869.       local
  3870.      sp: POSITION;
  3871.      hc: COMMENT;
  3872.      al: ARRAY[ASSERTION];
  3873.      ea: E_ENSURE;
  3874.      
  3875.       do
  3876.      if a_keyword(fz_obsolete) then
  3877.         if a_manifest_string then
  3878.            tmp_feature.set_obsolete_mark(last_manifest_string);
  3879.         else
  3880.            fcp("Obsolete manifest string expected.");
  3881.         end;
  3882.      end;
  3883.      tmp_feature.set_header_comment(get_comments);
  3884.      if a_keyword(fz_require) then
  3885.         !!sp.make(start_line,start_column);
  3886.         if a_keyword(fz_else) then
  3887.            hc := get_comments;
  3888.            tmp_feature.set_require_else(sp,hc,a_assertion);
  3889.         else
  3890.            hc := get_comments;
  3891.            tmp_feature.set_require(sp,hc,a_assertion);
  3892.         end;
  3893.      end;
  3894.      if a_keyword(fz_local) then
  3895.         a_local_var_list;
  3896.      end;
  3897.      Result := a_routine_body; 
  3898.      if a_keyword(fz_ensure) then
  3899.         !!sp.make(start_line,start_column);
  3900.         in_ensure := true;
  3901.         if a_keyword(fz_then) then
  3902.            hc := get_comments;
  3903.            al := a_assertion;
  3904.            if hc /= Void or else al /= Void then
  3905.           !!ea.make(sp,hc,al);
  3906.           ea.set_ensure_then;
  3907.            end;
  3908.            Result.set_ensure_assertion(ea);
  3909.         else
  3910.            hc := get_comments;
  3911.            al := a_assertion;
  3912.            if hc /= Void or else al /= Void then
  3913.           !!ea.make(sp,hc,al);
  3914.            end;
  3915.            Result.set_ensure_assertion(ea);
  3916.         end;
  3917.         in_ensure := false;
  3918.      end;
  3919.      if a_keyword(fz_rescue) then
  3920.         in_rescue := true;
  3921.         Result.set_rescue_compound(a_compound2(fz_rescue,fz_end));
  3922.         in_rescue := false;
  3923.      else
  3924.         if not a_keyword(fz_end) then
  3925.            wcp("A routine must be ended with %"end%".");
  3926.         end;
  3927.      end; 
  3928.      local_vars := Void;
  3929.       end;
  3930.    
  3931.    a_routine_body: ROUTINE is
  3932.      --++ routine_body -> "deferred" |
  3933.      --++                 "external" external |
  3934.      --++                 "do" compound |
  3935.      --++                 "once" compound
  3936.      --++
  3937.       do   
  3938.      if a_keyword(fz_deferred) then
  3939.         last_base_class.set_is_deferred;
  3940.         Result := tmp_feature.to_deferred_routine;
  3941.      elseif a_keyword(fz_external) then
  3942.         Result := a_external;
  3943.      elseif a_keyword(fz_do) then
  3944.         tmp_feature.set_routine_body(a_compound1);
  3945.         Result := tmp_feature.to_procedure_or_function;
  3946.      elseif a_keyword(fz_once) then
  3947.         inside_once_function := true;
  3948.         tmp_feature.set_routine_body(a_compound1);
  3949.         Result := tmp_feature.to_once_routine;
  3950.      else
  3951.         fcp("Routine body expected.");
  3952.      end;
  3953.       end;
  3954.    
  3955.    a_r1(left_part: like last_expression) is
  3956.      --++ r1 -> "implies" e1 r1 |
  3957.      --++       ^
  3958.      --++
  3959.       local
  3960.      infix_implies: CALL_INFIX_IMPLIES;
  3961.      sp: POSITION;
  3962.       do
  3963.      if a_keyword(us_implies) then
  3964.         !!sp.make(start_line,start_column);
  3965.         if a_e1 then
  3966.            !!infix_implies.make(left_part,sp,last_expression);
  3967.            a_r1(infix_implies);
  3968.         else
  3969.            error(sp,"Expression expected after 'implies'.");
  3970.         end;
  3971.      else
  3972.         last_expression := left_part;
  3973.      end;
  3974.       end;
  3975.    
  3976.    a_r2(left_part: like last_expression) is
  3977.      --++ r2 -> "or else" e2 r2 |
  3978.      --++       "or" e2 r2 |
  3979.      --++       "xor" e2 r2 |
  3980.      --++       ^
  3981.      --++
  3982.       local
  3983.      infix_or_else: CALL_INFIX_OR_ELSE;
  3984.      infix_or: CALL_INFIX_OR;
  3985.      infix_xor: CALL_INFIX_XOR;
  3986.      sp: POSITION;
  3987.       do
  3988.      if a_keyword(us_or) then
  3989.         !!sp.make(start_line,start_column);
  3990.         if a_keyword(fz_else) then
  3991.            if a_e2 then
  3992.           !!infix_or_else.make(left_part,sp,last_expression);
  3993.           a_r2(infix_or_else);
  3994.            else
  3995.           err_exp(sp,us_or_else); 
  3996.            end;
  3997.         else
  3998.            if a_e2 then
  3999.           !!infix_or.make(left_part,sp,last_expression);
  4000.           a_r2(infix_or);
  4001.            else
  4002.           err_exp(sp,us_or); 
  4003.            end;
  4004.         end;
  4005.      elseif a_keyword(us_xor) then
  4006.         !!sp.make(start_line,start_column);
  4007.         if a_e2 then
  4008.            !!infix_xor.make(left_part,sp,last_expression);
  4009.            a_r2(infix_xor);
  4010.         else
  4011.            err_exp(sp,us_xor); 
  4012.         end;
  4013.      else
  4014.         last_expression := left_part;
  4015.      end;
  4016.       end;
  4017.    
  4018.    a_r3(left_part: like last_expression) is
  4019.      --++ r3 -> "and then" e3 r3 |
  4020.      --++       "and" e3 r3 |
  4021.      --++       ^
  4022.      --++
  4023.       local
  4024.      infix_and_then: CALL_INFIX_AND_THEN;
  4025.      infix_and: CALL_INFIX_AND;
  4026.      sp: POSITION;
  4027.       do
  4028.      if a_keyword(us_and) then
  4029.         !!sp.make(start_line,start_column);
  4030.         if a_keyword(fz_then) then
  4031.            if a_e3 then
  4032.           !!infix_and_then.make(left_part,sp,last_expression);
  4033.           a_r3(infix_and_then);
  4034.            else
  4035.           err_exp(sp,us_and_then); 
  4036.            end;
  4037.         else
  4038.            if a_e3 then
  4039.           !!infix_and.make(left_part,sp,last_expression);
  4040.           a_r3(infix_and);
  4041.            else
  4042.           err_exp(sp,us_and); 
  4043.            end;
  4044.         end;
  4045.      else
  4046.         last_expression := left_part;
  4047.      end;
  4048.       end;
  4049.    
  4050.    a_r4(left_part: like last_expression) is
  4051.      --++ r4 -> "=" e4 r4 |
  4052.      --++       "/=" e4 r4 |
  4053.      --++       "<=" e4 r4 |
  4054.      --++       "<" e4 r4 |
  4055.      --++       ">=" e4 r4 |
  4056.      --++       ">" e4 r4 |
  4057.      --++       ^
  4058.      --++
  4059.       local
  4060.      infix_eq: CALL_INFIX_EQ;
  4061.      infix_neq: CALL_INFIX_NEQ;
  4062.      infix_le: CALL_INFIX_LE;
  4063.      infix_lt: CALL_INFIX_LT;
  4064.      infix_ge: CALL_INFIX_GE;
  4065.      infix_gt: CALL_INFIX_GT;
  4066.      sp: POSITION;
  4067.       do
  4068.      if skip1('=') then
  4069.         !!sp.make(start_line,start_column);
  4070.         if a_e4 then
  4071.            !!infix_eq.make(left_part,sp,last_expression);
  4072.            a_r4(infix_eq);
  4073.         else
  4074.            err_exp(sp,us_eq);
  4075.         end;
  4076.      elseif skip2('/','=') then
  4077.         !!sp.make(start_line,start_column);
  4078.         if a_e4 then
  4079.            !!infix_neq.make(left_part,sp,last_expression);
  4080.            a_r4(infix_neq);
  4081.         else
  4082.            err_exp(sp,us_neq);
  4083.         end;
  4084.      elseif skip2('<','=') then
  4085.         !!sp.make(start_line,start_column);
  4086.         if a_e4 then
  4087.            !!infix_le.make(left_part,sp,last_expression);
  4088.            a_r4(infix_le);
  4089.         else
  4090.            err_exp(sp,us_le);
  4091.         end;
  4092.      elseif skip2('>','=') then
  4093.         !!sp.make(start_line,start_column);
  4094.         if a_e4 then
  4095.            !!infix_ge.make(left_part,sp,last_expression);
  4096.            a_r4(infix_ge);
  4097.         else
  4098.            err_exp(sp,us_ge);
  4099.         end;
  4100.      elseif skip1('<') then
  4101.         !!sp.make(start_line,start_column);
  4102.         if a_e4 then
  4103.            !!infix_lt.make(left_part,sp,last_expression);
  4104.            a_r4(infix_lt);
  4105.         else
  4106.            err_exp(sp,us_lt);
  4107.         end;
  4108.      elseif skip1unless2('>','>') then 
  4109.         !!sp.make(start_line,start_column);
  4110.         if a_e4 then
  4111.            !!infix_gt.make(left_part,sp,last_expression);
  4112.            a_r4(infix_gt);
  4113.         else
  4114.            err_exp(sp,us_gt);
  4115.         end;
  4116.      else
  4117.         last_expression := left_part;
  4118.      end;
  4119.       end;
  4120.    
  4121.    a_r5(left_part: like last_expression) is
  4122.      --++ r5 -> "+" e5 r5 |
  4123.      --++       "-" e5 r5 |
  4124.      --++       ^
  4125.      --++
  4126.       local
  4127.      infix_plus: CALL_INFIX_PLUS;
  4128.      infix_minus: CALL_INFIX_MINUS;
  4129.      sp: POSITION;
  4130.       do
  4131.      if skip1('+') then
  4132.         !!sp.make(start_line,start_column);
  4133.         if a_e5 then
  4134.            !!infix_plus.make(left_part,sp,last_expression);
  4135.            a_r5(infix_plus);
  4136.         else
  4137.            err_exp(sp,us_plus); 
  4138.         end;
  4139.      elseif skip1('-') then
  4140.         !!sp.make(start_line,start_column);
  4141.         if a_e5 then
  4142.            !!infix_minus.make(left_part,sp,last_expression);
  4143.            a_r5(infix_minus);
  4144.         else
  4145.            err_exp(sp,us_minus); 
  4146.         end;
  4147.      else
  4148.         last_expression := left_part;
  4149.      end;
  4150.       end;
  4151.    
  4152.    a_r6(left_part: like last_expression) is
  4153.      --++ r6 -> "*" e6 r6 |
  4154.      --++       "//" e6 r6 |
  4155.      --++       "\\" e6 r6 |
  4156.      --++       "/" e6 r6 |
  4157.      --++       ^
  4158.      --++
  4159.       local
  4160.      infix_times: CALL_INFIX_TIMES;
  4161.      infix_int_div: CALL_INFIX_INT_DIV;
  4162.      infix_int_rem: CALL_INFIX_INT_REM;
  4163.      infix_div: CALL_INFIX_DIV;
  4164.      sp: POSITION;
  4165.       do
  4166.      if skip1('*') then
  4167.         !!sp.make(start_line,start_column);
  4168.         if a_e6 then
  4169.            !!infix_times.make(left_part,sp,last_expression);
  4170.            a_r6(infix_times);
  4171.         else
  4172.            err_exp(sp,us_muls); 
  4173.         end;
  4174.      elseif skip2('/','/') then
  4175.         !!sp.make(start_line,start_column);
  4176.         if a_e6 then
  4177.            !!infix_int_div.make(left_part,sp,last_expression);
  4178.            a_r6(infix_int_div);
  4179.         else
  4180.            err_exp(sp,"//"); 
  4181.         end;
  4182.      elseif skip2('\','\') then
  4183.         !!sp.make(start_line,start_column);
  4184.         if a_e6 then
  4185.            !!infix_int_rem.make(left_part,sp,last_expression);
  4186.            a_r6(infix_int_rem);
  4187.         else
  4188.            err_exp(sp,"\\"); 
  4189.         end;
  4190.      elseif skip1unless2('/','=') then 
  4191.         !!sp.make(start_line,start_column);
  4192.         if a_e6 then
  4193.            !!infix_div.make(left_part,sp,last_expression);
  4194.            a_r6(infix_div);
  4195.         else
  4196.            err_exp(sp,us_slash); 
  4197.         end;
  4198.      else
  4199.         last_expression := left_part;
  4200.      end;
  4201.       end;
  4202.    
  4203.       a_r7(left_part: like last_expression) is
  4204.         --++ r7 -> "^" e7 r7 |
  4205.         --++       ^
  4206.         --++
  4207.          local
  4208.             sp: POSITION;
  4209.          do
  4210.           if skip1('^') then
  4211.             !!sp.make(start_line,start_column);
  4212.             if a_e7 then
  4213.               a_r7(last_expression);
  4214.               !CALL_INFIX_POWER!last_expression.make(left_part,sp,last_expression);
  4215.             else
  4216.               err_exp(sp,"^"); 
  4217.             end;
  4218.           else
  4219.             last_expression := left_part;
  4220.           end;
  4221.          end;
  4222.  
  4223.    a_r8(left_part: like last_expression) is
  4224.      --++ r8 -> free_operator e8 r8 |
  4225.      --++       ^
  4226.      --++
  4227.       local
  4228.      infix_name: INFIX_NAME;
  4229.      infix_freeop: CALL_INFIX_FREEOP;
  4230.       do
  4231.      if a_free_operator then
  4232.         infix_name := tmp_name.to_infix_name_use;
  4233.         if a_e8 then
  4234.            !!infix_freeop.make(left_part,infix_name,last_expression);
  4235.            a_r8(infix_freeop);
  4236.         else
  4237.            err_exp(infix_name.start_position,infix_name.to_string); 
  4238.         end;
  4239.      else
  4240.         last_expression := left_part;
  4241.      end;
  4242.       end;
  4243.    
  4244.    a_r10(do_instruction: BOOLEAN; t: EXPRESSION; fn: FEATURE_NAME; 
  4245.          eal: EFFECTIVE_ARG_LIST) is
  4246.      --++ r10 -> "." after_a_dot |
  4247.      --++        ^ 
  4248.      --++
  4249.       do
  4250.      if skip1unless2('.','.') then
  4251.         a_after_a_dot(do_instruction,to_call(t,fn,eal));
  4252.      else
  4253.         if do_instruction then
  4254.            last_instruction := to_proc_call(t,fn,eal);
  4255.            last_expression := Void;
  4256.         else
  4257.            last_expression := to_call(t,fn,eal);
  4258.            last_instruction := Void;
  4259.         end;
  4260.      end;
  4261.       end;
  4262.  
  4263.    a_strip: BOOLEAN is
  4264.      --++ a_strip -> "strip" "(" {identifier "," ...} ")"
  4265.       local
  4266.      sp: POSITION;
  4267.       do
  4268.      if a_keyword(fz_strip) then
  4269.         !!sp.make(start_line,start_column);
  4270.         if skip1('(') then
  4271.            ok := a_feature_name_list; 
  4272.            !E_STRIP!last_expression.make(sp,last_feature_name_list);
  4273.            if not skip1(')') then
  4274.           fcp("')' expected to end a strip expression.");
  4275.            end;
  4276.            Result := true;
  4277.         else
  4278.            fcp("'(' expected to begin a strip list.");
  4279.         end;
  4280.      end;
  4281.       end;
  4282.    
  4283.    a_tag_mark: BOOLEAN is
  4284.      --++ tag_mark -> identifier ":"
  4285.      --++
  4286.       do
  4287.      if a_identifier then
  4288.         if skip1unless2(':','=') then
  4289.            Result := true;
  4290.            last_tag_mark := tmp_name.to_tag_name;
  4291.         else
  4292.            last_tag_mark := Void;
  4293.            go_back_at(tmp_name.li,tmp_name.co);
  4294.         end;
  4295.      else
  4296.         last_tag_mark := Void;
  4297.      end;
  4298.       end;
  4299.    
  4300.    a_then_part_list(ifthenelse: IFTHENELSE) is
  4301.      --++ then_part_list -> {then_part "elseif"}+
  4302.      --++
  4303.       do
  4304.      from
  4305.         if not a_then_part(ifthenelse) then
  4306.            fcp("In %"if ... then ...%".");
  4307.         end;
  4308.      until
  4309.         not a_keyword(fz_elseif)
  4310.      loop
  4311.         if not a_then_part(ifthenelse) then
  4312.            fcp("In %"elseif ... then ...%".");
  4313.         end;
  4314.      end;
  4315.       end;
  4316.    
  4317.    a_then_part(ifthenelse: IFTHENELSE): BOOLEAN is
  4318.      --++ then_part -> expression "then"
  4319.      --++
  4320.       local
  4321.      expression: EXPRESSION;
  4322.       do
  4323.      if a_expression then
  4324.         Result := true;
  4325.         expression := last_expression.add_comment(get_comments);
  4326.         if not a_keyword(fz_then) then
  4327.            wcp("Added %"then%".");
  4328.         end;
  4329.         ifthenelse.add_if_then(expression,a_compound1);
  4330.      end;
  4331.       end;
  4332.    
  4333.    a_type: BOOLEAN is
  4334.      --++ type -> "like" <anchor> | "expanded" class_type | BIT <constant>
  4335.      --++         type_formal_generic | class_type
  4336.      --++
  4337.       local 
  4338.      sp: POSITION;
  4339.      argument_name2: ARGUMENT_NAME2;
  4340.       do
  4341.      Result := true;
  4342.      if a_keyword(fz_like) then
  4343.         !!sp.make(start_line,start_column);
  4344.         if a_infix then
  4345.            !TYPE_LIKE_FEATURE!last_type.make(sp,last_infix);
  4346.         elseif a_prefix then
  4347.            !TYPE_LIKE_FEATURE!last_type.make(sp,last_prefix);
  4348.         elseif a_identifier then
  4349.            if a_current then
  4350.           !TYPE_LIKE_CURRENT!last_type.make(sp);
  4351.            elseif a_argument then
  4352.           argument_name2 ?= last_expression;
  4353.           !TYPE_LIKE_ARGUMENT!last_type.make(sp,argument_name2);
  4354.            else
  4355.           !TYPE_LIKE_FEATURE!last_type.make(sp,
  4356.                 tmp_name.to_simple_feature_name);
  4357.            end;
  4358.         else
  4359.            fcp("Anchor expected. An anchor could be `Current', %
  4360.            %a feature name or an argument name.");
  4361.         end;
  4362.      elseif a_keyword(fz_expanded) then
  4363.         !!sp.make(start_line,start_column);
  4364.         if a_class_type then
  4365.            !TYPE_EXPANDED!last_type.make(sp,last_class_type);
  4366.         else
  4367.            fcp("Must find a class type after %"expanded%".");
  4368.         end;
  4369.      elseif a_keyword(us_bit) then
  4370.         !!sp.make(start_line,start_column);
  4371.         if a_integer then
  4372.            !TYPE_BIT_1!last_type.make(sp,last_integer_constant);
  4373.         elseif a_identifier then
  4374.            !TYPE_BIT_2!last_type.make(sp,tmp_name.to_simple_feature_name);
  4375.         else
  4376.            fcp("Expected constant for BIT_N type declaration.");
  4377.         end;
  4378.      elseif a_type_formal_generic then
  4379.         last_type := last_type_formal_generic;
  4380.      elseif a_class_type then
  4381.         last_type := last_class_type;
  4382.      else
  4383.         Result := false;
  4384.      end;
  4385.       end;
  4386.    
  4387.    a_unary: BOOLEAN is
  4388.      --++ unary -> "not" | "+" | "-"
  4389.      --++
  4390.       do
  4391.      if a_keyword(us_not) then
  4392.         !!last_prefix.make(us_not,pos(start_line,start_column));
  4393.         Result := true;
  4394.      elseif skip1('+') then
  4395.         !!last_prefix.make(us_plus,pos(start_line,start_column));
  4396.         Result := true;
  4397.      elseif skip1('-') then
  4398.         !!last_prefix.make(us_minus,pos(start_line,start_column));
  4399.         Result := true;
  4400.      end;
  4401.       end;
  4402.       
  4403.    a_when_part(i: E_INSPECT): BOOLEAN is
  4404.      --++ when_part -> "when" {when_part_item "," ...} then compound
  4405.      --++
  4406.      --++ when_part_item -> constant ".." constant |
  4407.      --++                   constant
  4408.      --++
  4409.      --++ constant -> character_constant | integer_constant | identifier
  4410.      --++
  4411.       local
  4412.      state: INTEGER;
  4413.      -- state 0 : sepator read, waiting a constant or "then".
  4414.      -- state 1 : first constant read.
  4415.      -- state 2 : ".." read.
  4416.      -- state 3 : slice read.
  4417.      -- state 4 : end.
  4418.      e_when: E_WHEN;
  4419.      constant: EXPRESSION;
  4420.       do
  4421.      if a_keyword(fz_when) then
  4422.         from
  4423.            Result := true;
  4424.            !!e_when.make(pos(start_line,start_column),get_comments);
  4425.         until
  4426.            state > 3
  4427.         loop
  4428.            inspect
  4429.           state
  4430.            when 0 then
  4431.           if a_constant then
  4432.              constant := last_expression;
  4433.              state := 1;
  4434.           elseif a_keyword(fz_then) then
  4435.              if constant /= Void then
  4436.             e_when.add_value(constant);
  4437.              end;
  4438.              e_when.set_compound(a_compound1);
  4439.              i.add_when(e_when);
  4440.              state := 4;
  4441.           elseif cc = ',' then
  4442.              wcp(em7);
  4443.              ok := skip1(',');
  4444.           else
  4445.              fcp(em4);
  4446.              state := 4;
  4447.           end;
  4448.            when 1 then
  4449.           if a_keyword(fz_then) then
  4450.              if constant /= Void then
  4451.             e_when.add_value(constant);
  4452.              end;
  4453.              e_when.set_compound(a_compound1);
  4454.              i.add_when(e_when);
  4455.              state := 4;
  4456.           elseif skip2('.','.') then
  4457.              state := 2;
  4458.           elseif skip1(',') then
  4459.              e_when.add_value(constant);
  4460.              constant := Void;
  4461.              state := 0;
  4462.           else
  4463.              fcp(em4);
  4464.              state := 4;
  4465.           end;
  4466.            when 2 then
  4467.           if a_constant then
  4468.              e_when.add_slice(constant,last_expression);
  4469.              constant := Void;
  4470.              state := 3;
  4471.           else
  4472.              fcp(em4);
  4473.              state := 4;
  4474.           end;
  4475.            else -- state = 3
  4476.           if skip1(',') then
  4477.              state := 0;
  4478.           elseif a_keyword(fz_then) then
  4479.              e_when.set_compound(a_compound1);
  4480.              i.add_when(e_when);
  4481.              state := 4;
  4482.           elseif a_constant then
  4483.              constant := last_expression;
  4484.              warning(tmp_name.start_position,em5);
  4485.              state := 1;
  4486.           else
  4487.              fcp(em4);
  4488.              state := 4;
  4489.           end;
  4490.            end;
  4491.         end;
  4492.      end;
  4493.       end;
  4494.    
  4495. feature {NONE}
  4496.    
  4497.    to_call(t: EXPRESSION; fn: FEATURE_NAME; 
  4498.            eal: EFFECTIVE_ARG_LIST): EXPRESSION is
  4499.       require
  4500.      t /= Void;
  4501.       do
  4502.      if fn = Void then
  4503.         check
  4504.            eal = Void;
  4505.         end;
  4506.         Result := t;
  4507.      elseif eal = Void then
  4508.         !CALL_0_C!Result.make(t,fn);
  4509.      elseif eal.count = 1 then
  4510.         !CALL_1_C!Result.make(t,fn,eal);
  4511.      else
  4512.         !CALL_N!Result.make(t,fn,eal);
  4513.      end;
  4514.       end;
  4515.  
  4516.    to_proc_call(t: EXPRESSION; fn: FEATURE_NAME; 
  4517.                 eal: EFFECTIVE_ARG_LIST): PROC_CALL is
  4518.       do
  4519.      if fn = Void then
  4520.         fcp("An expression has a result value. %
  4521.         %This is not an instruction.");
  4522.      elseif eal = Void then
  4523.         !PROC_CALL_0!Result.make(t,fn);
  4524.      elseif eal.count = 1 then
  4525.         !PROC_CALL_1!Result.make(t,fn,eal);
  4526.      else
  4527.         !PROC_CALL_N!Result.make(t,fn,eal);
  4528.      end;
  4529.       end;
  4530.  
  4531. feature {NONE}
  4532.  
  4533.    wcpefnc(old_name, new_name: STRING) is
  4534.       do
  4535.      eh.append("For readability, the keyword %"");
  4536.      eh.append(old_name);
  4537.      eh.append("%" is now %"");
  4538.      eh.append(new_name);
  4539.      wcp("%". You should update your Eiffel code now.");
  4540.       end;
  4541.  
  4542. feature {NONE}
  4543.    
  4544.    em1 : STRING is "Underscore in fractionnal part must group 3 digits.";
  4545.    em2 : STRING is "Feature name expected.";
  4546.    em3 : STRING is "Index value expected (%"indexing ...%").";
  4547.    em4 : STRING is "Error in inspect.";
  4548.    em5 : STRING is "Added %",%".";
  4549.    em6 : STRING is "Added %";%".";
  4550.    em7 : STRING is "Unexpected comma (deleted)."   
  4551.    em8 : STRING is "Unexpected new line in manifest string.";
  4552.    em9 : STRING is "Underscore in number must group 3 digits.";
  4553.    em10: STRING is "Bad character constant.";
  4554.    em11: STRING is "Bad clients list.";
  4555.    em12: STRING is "Deleted extra coma.";
  4556.    em13: STRING is "Deleted extra separator.";
  4557.    em15: STRING is "Class name should use only uppercase letters.";
  4558.    em16: STRING is "Name of the current class expected.";
  4559.    em17: STRING is "Feature name expected after '$' (VUAR.4).";
  4560.    em18: STRING is "Type mark expected.";
  4561.    em19: STRING is "Added %" here.";
  4562.    em20: STRING is "Unexpected character."   
  4563.  
  4564. feature {NONE}
  4565.  
  4566.    forbidden_class: ARRAY[STRING] is
  4567.       once
  4568.      Result := <<us_none>>;
  4569.       end;
  4570.  
  4571.    lcs: STRING is
  4572.       -- Last Comment String.
  4573.       once
  4574.      !!Result.make(80);
  4575.       end;
  4576.  
  4577.    tmp_string: STRING is
  4578.       once
  4579.      !!Result.make(80);
  4580.       end;
  4581.  
  4582. feature {NONE}
  4583.  
  4584.    a_identifier1: BOOLEAN is
  4585.      -- Case Insensitive (option -case_insensitive).
  4586.       require
  4587.      case_insensitive
  4588.       local
  4589.      state: INTEGER;
  4590.      -- state 0 : first letter read.
  4591.      -- state 1 : end.
  4592.       do
  4593.      if cc.is_letter then
  4594.         from
  4595.            tmp_name.initialize(line,column);
  4596.            tmp_name.extend(cc.to_lower);
  4597.         until
  4598.            state > 0
  4599.         loop
  4600.            next_char;
  4601.            inspect
  4602.           cc
  4603.            when 'a'..'z','0'..'9','_' then
  4604.           tmp_name.extend(cc);
  4605.            when 'A'..'Z' then
  4606.           tmp_name.extend(cc.to_lower);
  4607.            else
  4608.           state := 1;
  4609.            end;
  4610.         end;
  4611.         if tmp_name.isa_keyword then
  4612.            from  
  4613.           state := tmp_name.count;
  4614.            until
  4615.           state = 0
  4616.            loop
  4617.           state := state - 1;
  4618.           prev_char;
  4619.            end;
  4620.         else
  4621.            Result := true;
  4622.            skip_comments;
  4623.         end;
  4624.      end;
  4625.       end;
  4626.    
  4627.    a_identifier2: BOOLEAN is
  4628.      -- Case Sensitivity for identifiers (default).
  4629.       require
  4630.      not case_insensitive
  4631.       local
  4632.      state: INTEGER;
  4633.      do_warning: BOOLEAN;
  4634.      -- state 0 : first letter read.
  4635.      -- state 1 : end.
  4636.       do
  4637.      if cc.is_letter then
  4638.         from
  4639.            tmp_name.initialize(line,column);
  4640.            tmp_name.extend(cc);
  4641.         until
  4642.            state > 0
  4643.         loop
  4644.            next_char;
  4645.            inspect
  4646.           cc
  4647.            when 'a'..'z','0'..'9','_' then
  4648.           tmp_name.extend(cc);
  4649.            when 'A'..'Z' then
  4650.           do_warning := true;
  4651.           tmp_name.extend(cc);
  4652.            else
  4653.           state := 1;
  4654.            end;
  4655.         end;
  4656.         if tmp_name.isa_keyword then
  4657.            from  
  4658.           state := tmp_name.count;
  4659.            until
  4660.           state = 0
  4661.            loop
  4662.           state := state - 1;
  4663.           prev_char;
  4664.            end;
  4665.         else
  4666.            Result := true;
  4667.            skip_comments;
  4668.            if do_warning then
  4669.           warning(tmp_name.start_position,
  4670.           "Identifier should use only lowercase letters.");
  4671.            end;
  4672.         end;
  4673.      end;
  4674.       end;
  4675.  
  4676. feature {COMPILE_TO_C,COMPILE_TO_JVM}
  4677.  
  4678.    set_drop_comments is
  4679.       do
  4680.      drop_comments := true;
  4681.       end;
  4682.  
  4683. feature {NONE}
  4684.  
  4685.    to_frozen_feature_name is
  4686.       do
  4687.      !FROZEN_FEATURE_NAME!last_feature_name.make(last_feature_name);
  4688.       end;
  4689.  
  4690. feature {NONE}
  4691.  
  4692.    last_result: ABSTRACT_RESULT is
  4693.       local
  4694.      sp: POSITION;
  4695.       do
  4696.      sp := tmp_name.start_position;
  4697.      if inside_function then
  4698.         if inside_once_function then
  4699.            !ONCE_RESULT!Result.make(sp);
  4700.         else
  4701.            !ORDINARY_RESULT!Result.make(sp);
  4702.         end;
  4703.      else
  4704.         eh.add_position(sp);
  4705.         fatal_error("`Result' must only be used inside a function.");
  4706.      end;
  4707.       ensure
  4708.      Result /= Void
  4709.       end;
  4710.    
  4711. feature {NONE}
  4712.  
  4713.    faof: FIXED_ARRAY[E_FEATURE] is
  4714.       once
  4715.      !!Result.with_capacity(256);
  4716.       end;
  4717.  
  4718. feature {NONE}
  4719.  
  4720.    singleton_memory: EIFFEL_PARSER is
  4721.       once
  4722.      Result := Current;
  4723.       end;
  4724.  
  4725. invariant
  4726.  
  4727.    is_real_singleton: Current = singleton_memory
  4728.    
  4729. end -- EIFFEL_PARSER
  4730.  
  4731.